Skip to content

Commit

Permalink
MDL_renderer: Added support for cubic B-spline curve primitives and t…
Browse files Browse the repository at this point in the history
…he MDL hair BSDF.

Added system_mdl_hair.txt, scene_mdl_hair.txt, fur.hair model, and hair BSDF example materials used in that scene.
The example can load *.hair models and converts the line strips in them to cubic B-spline curve control points.
  • Loading branch information
droettger committed Mar 21, 2023
1 parent db33e25 commit f0606d8
Show file tree
Hide file tree
Showing 43 changed files with 2,758 additions and 195 deletions.
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ The renderer implementation has the following limitations at this time:
* Volume absorption and scattering assumes homogeneous volume coefficients. There's simply no volume data primitive in the scene to sample heterogeneous coefficients from.
* Volume scattering emission intensity not implemented. Goes along with heterogeneous volume scattering support.
* Geometry displacement not implemented. To be revisited once Displacement Micro Meshes (DMM) are supported by OptiX.
* Hair BSDF not implemented. The renderer currently supports one texture coordinate, hair BSDF requires two to be fully featured and that'll increase the cost for every shader, so it's deferred into a separate example.
* UV-tile and animation textures not implemented.
* rounded_corner_normal() not implemented. That cannot be done by the automatic code generation for the geometry.normal expression.
* Spot and light profile `global_distribution: true` not supported by the MDL SDK code generation. Lights will be black then. The renderer supports own point lights with spot and IES distribution though.
Expand All @@ -151,6 +150,19 @@ Everything else inside the MDL specifications should just work!
![MDL_renderer with MDL materials](./apps/MDL_renderer/MDL_renderer_demo.png)
![MDL_renderer with vMaterials](./apps/MDL_renderer/MDL_renderer_vMaterials.png)

The MDL_renderer has now been updated to also support cubic B-spline curve primitives and the MDL Hair BSDF.

Because that requires two texture coordinates to be fully featured, the `NUM_TEXTURE_SPACES` define has been added to the `config.h` to allow switching between one and two texture coordinates. If you do not need the hair BSDF, you can set `NUM_TEXTURE_SPACES` to 1 for a little more performance.

The MDL hair BSDF supports a fully parameterized fiber surface accessible via the `state::texture_coordinate(0)` providing (uFiber, vFiber, thickness) values, which allows implementing parameter changes along the whole fiber and even aound it. The provided `mdl/bsdf_hair_uv.mdl` material shows this by placing tiny arrows on the fibers pointing from root to tip.

Additionally the second texture coordinate `state::texture_coordinate(1)` defines a fixed texture coordinate per fiber, which allows coloring of individual fibers depending on some texture value. The image below used a Perlin noise function to produce highlights in the hair, resp. a 2D texture to color the fibers of the `fur.hair` model (included).

The renderer currently loads only `*.hair` models which do not have texture coordinates. The example auto-generates a 2D coordinate with a cubemap projection from the root points' center coordinate. There are better ways to do this when actually growing hair from surfaces, not done in this example. Transparency and color values of *.hair files are ignored. The assigned MDL hair material defines these properties.

![MDL_renderer with hair rendering](./apps/MDL_renderer/MDL_renderer_highlights.png)
![MDL_renderer with fur rendering](./apps/MDL_renderer/MDL_renderer_fur.png)

**User Interaction inside the examples**:
* Left Mouse Button + Drag = Orbit (around center of interest)
* Middle Mouse Button + Drag = Pan (The mouse ratio field in the GUI defines how many pixels is one unit.)
Expand Down Expand Up @@ -331,6 +343,11 @@ For a lot more complex materials (this scene requires about 5.4 GB of VRAM), the

* `MDL_renderer.exe -s system_mdl_vMaterials.txt -d scene_mdl_vMaterials.txt`

For the curves rendering with MDL hair BSDF materials, issue the command line. That will display a sphere with cubic B-spline curves using a red hair material lit by an area light from above. Please read the `scene_mdl_hair.txt? for other possible material and model configurations.

* `MDL_renderer.exe -s system_mdl_hair.txt -d scene_mdl_hair.txt`


# Pull Requests

NVIDIA is happy to review and consider pull requests for merging into the main tree of the optix_apps for bug fixes and features. Before providing a pull request to NVIDIA, please note the following:
Expand Down
5 changes: 5 additions & 0 deletions apps/MDL_renderer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ set( HEADERS
inc/CheckMacros.h
inc/CompileResult.h
inc/Device.h
inc/Hair.h
inc/LightGUI.h
inc/LoaderIES.h
inc/MaterialMDL.h
Expand All @@ -141,7 +142,9 @@ set( SOURCES
src/Assimp.cpp
src/Box.cpp
src/Camera.cpp
src/Curves.cpp
src/Device.cpp
src/Hair.cpp
src/LoaderIES.cpp
src/main.cpp
src/MaterialMDL.cpp
Expand Down Expand Up @@ -181,6 +184,8 @@ set( SHADERS_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/shaders/camera_definition.h
${CMAKE_CURRENT_SOURCE_DIR}/shaders/compositor_data.h
${CMAKE_CURRENT_SOURCE_DIR}/shaders/config.h
${CMAKE_CURRENT_SOURCE_DIR}/shaders/curve.h
${CMAKE_CURRENT_SOURCE_DIR}/shaders/curve_attributes.h
${CMAKE_CURRENT_SOURCE_DIR}/shaders/function_indices.h
${CMAKE_CURRENT_SOURCE_DIR}/shaders/light_definition.h
${CMAKE_CURRENT_SOURCE_DIR}/shaders/material_definition_mdl.h
Expand Down
Binary file added apps/MDL_renderer/MDL_renderer_fur.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/MDL_renderer/MDL_renderer_highlights.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 7 additions & 3 deletions apps/MDL_renderer/inc/Device.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@ struct DeviceAttribute
int concurrentManagedAccess;
int computePreemptionSupported;
int canUseHostPointerForRegisteredMem;
int canUseStreamMemOps;
int canUse64BitStreamMemOps;
int canUseStreamWaitValueNor;
int cooperativeLaunch;
Expand Down Expand Up @@ -229,6 +228,9 @@ enum ProgramGroupId
// 3 = emission, cutout
PGID_HIT_RADIANCE_3,
PGID_HIT_SHADOW_3,
// 4 = cubic B-spline curves.
PGID_HIT_CURVES,
PGID_HIT_CURVES_SHADOW,

// Direct Callables
// Lens shader
Expand All @@ -252,7 +254,8 @@ enum ProgramGroupId
enum PrimitiveType
{
PT_UNKNOWN, // It's an error when this is still set.
PT_TRIANGLES
PT_TRIANGLES,
PT_CURVES
};


Expand All @@ -271,7 +274,7 @@ struct GeometryData
info = {};
}

PrimitiveType primitiveType; // Triangles ony in this renderer.
PrimitiveType primitiveType; // Triangles or cubic B-spline curves. Used to pick the correct hit record inside the SBT.
int owner; // The device index which originally allocated all device side memory below. Needed when sharing GeometryData, resp. when freeing it.
OptixTraversableHandle traversable; // The traversable handle for this GAS. Assigned to the Instance above it.
CUdeviceptr d_attributes; // Array of VertexAttribute structs.
Expand Down Expand Up @@ -341,6 +344,7 @@ class Device
void initLights(const std::vector<LightGUI>& lightsGUI, const std::vector<GeometryData>& geometryData, const unsigned int stride, const unsigned int index); // Must be called after initScene()!

GeometryData createGeometry(std::shared_ptr<sg::Triangles> geometry);
GeometryData createGeometry(std::shared_ptr<sg::Curves> geometry);
void destroyGeometry(GeometryData& data);
void createInstance(const GeometryData& geometryData, const InstanceData& data, const float matrix[12]);
void createTLAS();
Expand Down
129 changes: 129 additions & 0 deletions apps/MDL_renderer/inc/Hair.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Copyright (c) 2023, 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

#ifndef HAIR_H
#define HAIR_H

// Hair file format and models courtesy of Cem Yuksel: http://www.cemyuksel.com/research/hairmodels/

// For the float3
#include <cuda_runtime.h>

#include <string>
#include <vector>

#define HAS_SEGMENTS_ARRAY (1 << 0)
#define HAS_POINTS_ARRAY (1 << 1)
#define HAS_THICKNESS_ARRAY (1 << 2)
#define HAS_TRANSPARENCY_ARRAY (1 << 3)
#define HAS_COLOR_ARRAY (1 << 4)

// Note that the Hair class setter interfaces are unused in this example but allow generating *.hair files easily.
//
// At minimum that needs an array of float3 points and the matching header values.
// This renderer doesn't care about the transparency and color inside the *.hair model file.
// The material is defined by the assigned MDL hair BSDF material.
// Not setting the color might result in black in other applications.
//
// Example for setting individual cubic B-spline curves with four control points each.
// ... // Build your std::vector<float3> pointsArray here.
//Hair hair;
//hair.setNumStrands(numStrands); // Number of hair strands inside the file.
//hair.setNumSegments(3); // Cubic B-Splines with 4 control points each are 3 segments.
//hair.setPointsArray(pointsArray); // This defines the m_header.numPoints as well.
//hair.setThickness(thickness); // Constant thickness. Use setThicknessArray() if values differ along strands.
//hair.save(filename);

class Hair
{
// HAIR File Header (128 Bytes)
struct Header
{
char signature[4]; // Bytes 0-3 Must be "HAIR" in ascii code (48 41 49 52)
unsigned int numStrands; // Bytes 4-7 Number of hair strands as unsigned int
unsigned int numPoints; // Bytes 8-11 Total number of points of all strands as unsigned int
unsigned int bits; // Bytes 12-15 Bit array of data in the file
// Bit-0 is 1 if the file has segments array.
// Bit-1 is 1 if the file has points array (this bit must be 1).
// Bit-2 is 1 if the file has thickness array.
// Bit-3 is 1 if the file has transparency array.
// Bit-4 is 1 if the file has color array.
// Bit-5 to Bit-31 are reserved for future extension (must be 0).
unsigned int numSegments; // Bytes 16-19 Default number of segments of hair strands as unsigned int
// If the file does not have a segments array, this default value is used.
float thickness; // Bytes 20-23 Default thickness hair strands as float
// If the file does not have a thickness array, this default value is used.
float transparency; // Bytes 24-27 Default transparency hair strands as float
// If the file does not have a transparency array, this default value is used.
float3 color; // Bytes 28-39 Default color hair strands as float array of size 3
// If the file does not have a thickness array, this default value is used.
char information[88]; // Bytes 40-127 File information as char array of size 88 in ascii
};

public:
Hair();
//~Hair();

bool load(const std::string& filename);
bool save(const std::string& filename);

void setNumStrands(const unsigned int num);
unsigned int getNumStrands() const;

void setNumSegments(const unsigned int num);
void setSegmentsArray(const std::vector<unsigned short>& segments);
unsigned int getNumSegments(const unsigned int idxStrand) const;

void setPointsArray(const std::vector<float3>& points); // This also sets m_header.numPoints!
float3 getPoint(const unsigned int idx) const;

void setThickness(const float thickness);
void setThicknessArray(const std::vector<float>& thickness);
float getThickness(const unsigned int idx) const;

void setTransparency(const float transparency);
void setTransparencyArray(const std::vector<float>& transparency);
float getTransparency(const unsigned int idx) const;

void setColor(const float3 color);
void setColorArray(const std::vector<float3>& color);
float3 getColor(const unsigned int idx) const;

private:
Header m_header;

std::vector<unsigned short> m_segmentsArray; // Empty or size numStrands.
std::vector<float3> m_pointsArray; // Size numPoints.
std::vector<float> m_thicknessArray; // Empty or size numPoints.
std::vector<float> m_transparencyArray; // Empty or size numPoints.
std::vector<float3> m_colorArray; // Empty or size numPoints.
};

#endif // HAIR_H
28 changes: 26 additions & 2 deletions apps/MDL_renderer/inc/SceneGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
// For the vector types.
#include <cuda_runtime.h>

#include "shaders/curve_attributes.h"
#include "shaders/vertex_attributes.h"
#include "shaders/vector_math.h"

Expand All @@ -49,7 +50,8 @@ namespace sg
{
NT_GROUP,
NT_INSTANCE,
NT_TRIANGLES
NT_TRIANGLES,
NT_CURVES
};

class Node
Expand Down Expand Up @@ -93,9 +95,31 @@ namespace sg

private:
std::vector<TriangleAttributes> m_attributes;
std::vector<unsigned int> m_indices; // If m_indices.size() == 0, m_attributes are independent primitives. // Not actually supported in this renderer implementation.
std::vector<unsigned int> m_indices; // If m_indices.size() == 0, m_attributes are independent primitives (not actually supported in this renderer implementation!)
};

class Curves : public Node
{
public:
Curves(const unsigned int id);
//~Curves();

sg::NodeType getType() const;

bool createHair(std::string const& filename, const float scale);

void setAttributes(std::vector<CurveAttributes> const& attributes);
std::vector<CurveAttributes> const& getAttributes() const;

void setIndices(std::vector<unsigned int> const&);
std::vector<unsigned int> const& getIndices() const;

private:
std::vector<CurveAttributes> m_attributes;
std::vector<unsigned int> m_indices;
};


class Instance : public Node
{
public:
Expand Down
1 change: 1 addition & 0 deletions apps/MDL_renderer/inc/ShaderConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ struct ShaderConfiguration
bool use_volume_scattering;
bool is_cutout_opacity_constant;
bool use_cutout_opacity;
bool is_hair_bsdf_valid;

// The constant expression values:
bool thin_walled;
Expand Down
19 changes: 19 additions & 0 deletions apps/MDL_renderer/shaders/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,23 @@
#define INTEROP_MODE_TEX 1
#define INTEROP_MODE_PBO 2

// The number of supported texture coordinate slots inside MDL shaders (state::texture_*(i)).
// This makes the Mdl_state bigger which will cost performance!
// It's also less convenient to use the TBN ortho-normal basis.
// hair_bsdf() requires two texture coordinates to communicate the intersection results
// and a per fiber texture coordinate which can be used to color each hair individually.
// That's the whole reason for this define.
// HACK The renderer's vertex attributes are not acctually managing two distinct texture coordinates.
// The Mdl_state will simply duplicate the data of texture coordinate slot 0 to slot 1 everywhere except for the hair_bsdf().
#define NUM_TEXTURE_SPACES 2

// The number of float4 elements inside the texture_results cache. Default is 16.
// Used to configure the MDL backend's code generation with set_option("num_texture_results", ...)
// This value influences how many things can be precalculated inside the init() function.
// If the number of result elements in this array is lower than what is required,
// the expressions for the remaining results will be compiled into the sample() and evaluate() functions
// which will make the compilation and runtime performance slower.
// For very resource-heavy materials, experiment with bigger values.
#define NUM_TEXTURE_RESULTS 16

#endif // CONFIG_H
Loading

0 comments on commit f0606d8

Please sign in to comment.