├── version.txt ├── .gitignore ├── resources ├── mars1.jpg ├── mars2.jpg ├── mars3.jpg ├── mars4.jpg ├── earth1.jpg ├── earth2.jpg ├── earth3.jpg ├── earth4.jpg └── aa42437-21.pdf ├── examples ├── example_ttu2.hip └── example_atmosphere.hip ├── houdini ├── volumelayers │ ├── otls │ │ ├── VOP_bsdf.otl │ │ ├── approxmie.otl │ │ └── VOP_volumelayer.otl │ ├── vop │ │ └── volumelayer.json │ ├── help │ │ └── nodes │ │ │ └── vop │ │ │ ├── jparker--pbrrayleighphase.txt │ │ │ ├── jparker--volumelayerunpack.txt │ │ │ ├── jparker--volumelayermerge.txt │ │ │ ├── jparker--volumelayertoshadinglayer.txt │ │ │ ├── jparker--transmittoabsorb.txt │ │ │ ├── jparker--volumelayercomputelighting.txt │ │ │ ├── jparker--volumelayermix.txt │ │ │ ├── jparker--volumelayerpack.txt │ │ │ ├── jparker--volumelayerspacetransform.txt │ │ │ ├── jparker--volumelayeraddquantity.txt │ │ │ ├── jparker--scaleheightdensity.txt │ │ │ ├── jparker--pbrttu2phase.txt │ │ │ ├── jparker--volumelayeradjustmultiscatter.txt │ │ │ ├── jparker--pbrapproxmie.txt │ │ │ └── jparker--volumelayer.txt │ └── vex │ │ ├── CVex │ │ ├── rayleigh_eval.vfl │ │ ├── draine_eval.vfl │ │ ├── rayleigh_sample.vfl │ │ ├── ttu2_eval.vfl │ │ ├── ttu2_sample.vfl │ │ └── draine_sample.vfl │ │ └── include │ │ ├── ttu2.h │ │ ├── volumelayer.h │ │ └── approxmie.h └── volumelayers.json ├── INSTALL.md ├── LICENSE └── README.md /version.txt: -------------------------------------------------------------------------------- 1 | 1.3.6 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/backup/* 2 | rendergallery.db* 3 | backup 4 | galleries 5 | 6 | resources/**.pdf -------------------------------------------------------------------------------- /resources/mars1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parkerjon/jpVolumeLayers/HEAD/resources/mars1.jpg -------------------------------------------------------------------------------- /resources/mars2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parkerjon/jpVolumeLayers/HEAD/resources/mars2.jpg -------------------------------------------------------------------------------- /resources/mars3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parkerjon/jpVolumeLayers/HEAD/resources/mars3.jpg -------------------------------------------------------------------------------- /resources/mars4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parkerjon/jpVolumeLayers/HEAD/resources/mars4.jpg -------------------------------------------------------------------------------- /resources/earth1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parkerjon/jpVolumeLayers/HEAD/resources/earth1.jpg -------------------------------------------------------------------------------- /resources/earth2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parkerjon/jpVolumeLayers/HEAD/resources/earth2.jpg -------------------------------------------------------------------------------- /resources/earth3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parkerjon/jpVolumeLayers/HEAD/resources/earth3.jpg -------------------------------------------------------------------------------- /resources/earth4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parkerjon/jpVolumeLayers/HEAD/resources/earth4.jpg -------------------------------------------------------------------------------- /resources/aa42437-21.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parkerjon/jpVolumeLayers/HEAD/resources/aa42437-21.pdf -------------------------------------------------------------------------------- /examples/example_ttu2.hip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parkerjon/jpVolumeLayers/HEAD/examples/example_ttu2.hip -------------------------------------------------------------------------------- /examples/example_atmosphere.hip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parkerjon/jpVolumeLayers/HEAD/examples/example_atmosphere.hip -------------------------------------------------------------------------------- /houdini/volumelayers/otls/VOP_bsdf.otl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parkerjon/jpVolumeLayers/HEAD/houdini/volumelayers/otls/VOP_bsdf.otl -------------------------------------------------------------------------------- /houdini/volumelayers/otls/approxmie.otl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parkerjon/jpVolumeLayers/HEAD/houdini/volumelayers/otls/approxmie.otl -------------------------------------------------------------------------------- /houdini/volumelayers/otls/VOP_volumelayer.otl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parkerjon/jpVolumeLayers/HEAD/houdini/volumelayers/otls/VOP_volumelayer.otl -------------------------------------------------------------------------------- /houdini/volumelayers.json: -------------------------------------------------------------------------------- 1 | { 2 | "hpath": "$VEX_VOLUMELAYERS", 3 | "load_package_once": true, 4 | "enable": "houdini_version >= '17.5' and houdini_version < '22.0'", 5 | "version": "1.0.0", 6 | "env": [ 7 | { 8 | "VEX_VOLUMELAYERS": "$HOUDINI_PACKAGE_PATH/volumelayers" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | ### Installation Instructions 2 | 3 | 1. Create a folder in your Houdini user preferences folder called `packages`. For example at `C:\Users\user\Documents\houdini19.5\packages` 4 | 2. Copy the contents of the folder `houdini/volumelayers` into the newly created `packages` folder at `houdinixx.x/packages` and start / restart Houdini. 5 | 6 | For other installation options, see the following Houdini help links: 7 | 8 | https://www.sidefx.com/docs/houdini/ref/plugins.html 9 | https://www.sidefx.com/docs/houdini/basics/config_env.html 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /houdini/volumelayers/vop/volumelayer.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeDefinitions":[ 3 | { 4 | "type":"struct", 5 | "typeName":"VolumeLayer", 6 | "typeLabel":"VolumeLayer", 7 | "definitionCode": "#include ", 8 | "connectorColor":{ 9 | "type":"RGB", 10 | "data":[0.9,0.605,0.83 11 | ] 12 | }, 13 | "variables":[ 14 | { 15 | "typeName":"bsdf", 16 | "name":"F", 17 | "label":"BSDF" 18 | }, 19 | { 20 | "typeName":"vector", 21 | "name":"density", 22 | "label":"Density" 23 | }, 24 | { 25 | "typeName":"vector", 26 | "name":"Ce", 27 | "label":"Emission" 28 | } 29 | ] 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /houdini/volumelayers/help/nodes/vop/jparker--pbrrayleighphase.txt: -------------------------------------------------------------------------------- 1 | = PBR Rayleigh Phase Function = 2 | 3 | """ Generates a Rayleigh scattering phase function BSDF.""" 4 | 5 | == Overview == 6 | 7 | This operator implements the Rayleigh scattering phase function. This is the most common phase function used to simulate the scattering of light in the Earth's atmosphere. 8 | 9 | For more information see: 10 | 11 | [Rayleigh Scattering (Wikipedia)|https://en.wikipedia.org/wiki/Rayleigh_scattering] 12 | 13 | Citation: 14 | 15 | Frisvad, J. R. (2011). Importance sampling the Rayleigh phase function. Optical Society of America. Journal A: 16 | Optics, Image Science, and Vision, 28(12), 2436-2441. [https://doi.org/10.1364/JOSAA.28.002436] 17 | 18 | 19 | @parameters 20 | 21 | Component Label: 22 | #id: label 23 | BSDF component label. 24 | 25 | @outputs 26 | 27 | f: 28 | BSDF 29 | -------------------------------------------------------------------------------- /houdini/volumelayers/help/nodes/vop/jparker--volumelayerunpack.txt: -------------------------------------------------------------------------------- 1 | = Volume Layer Unpack = 2 | 3 | """Extracts VolumeLayer struct components.""" 4 | 5 | @outputs 6 | F: 7 | BSDF component 8 | 9 | density: 10 | VolumeLayer raw density component 11 | 12 | Ce: 13 | Emission component 14 | 15 | @related 16 | 17 | * [Volume Layer Merge|Node:vop/jparker--volumelayermerge] 18 | * [Volume Layer Shader|Node:vop/jparker--volumelayershader] 19 | * [Volume Layer Mix|Node:vop/jparker--volumelayermix] 20 | * [Volume Layer Add Quantity|Node:vop/jparker--volumelayeraddquantity] 21 | * [Volume Layer Compute Lighting|Node:vop/jparker--volumelayercomputelighting] 22 | * [Volume Layer to Shading Layer|Node:vop/jparker--volumelayertoshadinglayer] 23 | * [Volume Layer Pack|Node:vop/jparker--volumelayerpack] 24 | * [Volume Layer Adjust Multiscatter|Node:vop/jparker--volumelayeradjustmultiscatter] 25 | -------------------------------------------------------------------------------- /houdini/volumelayers/help/nodes/vop/jparker--volumelayermerge.txt: -------------------------------------------------------------------------------- 1 | = Volume Layer Merge = 2 | 3 | """Merge two volume layers.""" 4 | 5 | == Overview == 6 | 7 | This operator takes two VolumeLayer struct-based VOP nodes and adds them together in a physically correct way. 8 | 9 | @inputs 10 | A: 11 | VolumeLayer struct A 12 | 13 | B: 14 | VolumeLayer struct B 15 | 16 | @related 17 | 18 | * [Volume Layer Shader|Node:vop/jparker--volumelayershader] 19 | * [Volume Layer Mix|Node:vop/jparker--volumelayermix] 20 | * [Volume Layer Add Quantity|Node:vop/jparker--volumelayeraddquantity] 21 | * [Volume Layer Compute Lighting|Node:vop/jparker--volumelayercomputelighting] 22 | * [Volume Layer to Shading Layer|Node:vop/jparker--volumelayertoshadinglayer] 23 | * [Volume Layer Pack|Node:vop/jparker--volumelayerpack] 24 | * [Volume Layer Unpack|Node:vop/jparker--volumelayerunpack] 25 | * [Volume Layer Adjust Multiscatter|Node:vop/jparker--volumelayeradjustmultiscatter] 26 | -------------------------------------------------------------------------------- /houdini/volumelayers/help/nodes/vop/jparker--volumelayertoshadinglayer.txt: -------------------------------------------------------------------------------- 1 | = Volume Layer Add Quantity = 2 | 3 | """Add a component property to an input VolumeLayer struct.""" 4 | 5 | == Overview == 6 | 7 | This operator takes a VolumeLayer struct as input and converts it to a standard Houdini shading layer struct. 8 | 9 | @inputs 10 | volumelayer: 11 | VolumeLayer to convert to shading layer 12 | 13 | @related 14 | 15 | * [Volume Layer Merge|Node:vop/jparker--volumelayermerge] 16 | * [Volume Layer Shader|Node:vop/jparker--volumelayershader] 17 | * [Volume Layer Mix|Node:vop/jparker--volumelayermix] 18 | * [Volume Layer Add Quantity|Node:vop/jparker--volumelayeraddquantity] 19 | * [Volume Layer Compute Lighting|Node:vop/jparker--volumelayercomputelighting] 20 | * [Volume Layer Pack|Node:vop/jparker--volumelayerpack] 21 | * [Volume Layer Unpack|Node:vop/jparker--volumelayerunpack] 22 | * [Volume Layer Adjust Multiscatter|Node:vop/jparker--volumelayeradjustmultiscatter] 23 | -------------------------------------------------------------------------------- /houdini/volumelayers/help/nodes/vop/jparker--transmittoabsorb.txt: -------------------------------------------------------------------------------- 1 | = Transmission to Absorption = 2 | 3 | """ Converts volume transmission color to absorption coefficient.""" 4 | 5 | @inputs 6 | 7 | transmit: 8 | Transmission color. This is what absorption looks like visually when scattering is white. When converted to absorption, the value is non-linear: black values become near infinite absorption probabilities. 9 | 10 | @outputs 11 | 12 | absorb: 13 | Volume absorption coefficient. 14 | 15 | @related 16 | 17 | * [Volume Layer Merge|Node:vop/jparker--volumelayermerge] 18 | * [Volume Layer Shader|Node:vop/jparker--volumelayershader] 19 | * [Volume Layer Mix|Node:vop/jparker--volumelayermix] 20 | * [Volume Layer Add Quantity|Node:vop/jparker--volumelayeraddquantity] 21 | * [Volume Layer Compute Lighting|Node:vop/jparker--volumelayercomputelighting] 22 | * [Volume Layer to Shading Layer|Node:vop/jparker--volumelayertoshadinglayer] 23 | * [Volume Layer Unpack|Node:vop/jparker--volumelayerunpack] 24 | * [Volume Layer Pack|Node:vop/jparker--volumelayerpack] 25 | -------------------------------------------------------------------------------- /houdini/volumelayers/help/nodes/vop/jparker--volumelayercomputelighting.txt: -------------------------------------------------------------------------------- 1 | = Volume Layer Compute Lighting = 2 | 3 | """ Converts VolumeLayer struct to ShadingLayer struct and passes result into a "Compute Lighting" VOP.""" 4 | 5 | == Overview == 6 | 7 | This operator takes a VolumeLayer struct as input and converts it to material outputs and standard Houdini AOVs. 8 | 9 | This relies on the built-in [Compute Lighting|computelighting] node. See the help for that node for more details. 10 | 11 | @inputs 12 | volumelayer: 13 | VolumeLayer to modify 14 | 15 | @related 16 | 17 | * [Volume Layer Merge|Node:vop/jparker--volumelayermerge] 18 | * [Volume Layer Shader|Node:vop/jparker--volumelayershader] 19 | * [Volume Layer Mix|Node:vop/jparker--volumelayermix] 20 | * [Volume Layer Add Quantity|Node:vop/jparker--volumelayeraddquantity] 21 | * [Volume Layer to Shading Layer|Node:vop/jparker--volumelayertoshadinglayer] 22 | * [Volume Layer Pack|Node:vop/jparker--volumelayerpack] 23 | * [Volume Layer Unpack|Node:vop/jparker--volumelayerunpack] 24 | * [Volume Layer Adjust Multiscatter|Node:vop/jparker--volumelayeradjustmultiscatter] 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Jon Parker 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /houdini/volumelayers/help/nodes/vop/jparker--volumelayermix.txt: -------------------------------------------------------------------------------- 1 | = Volume Layer Mix = 2 | 3 | """Mix two volume layers.""" 4 | 5 | == Overview == 6 | 7 | This operator takes two VolumeLayer struct-based VOP nodes and mixes them together in a physically correct way. 8 | 9 | TIP: 10 | The "VolumeLayerMix" VEX function has more options for combining two VolumeLayer structs with individual weights for F, density and Ce. 11 | 12 | @inputs 13 | A: 14 | VolumeLayer struct A 15 | 16 | B: 17 | VolumeLayer struct B 18 | 19 | mix: 20 | Blend value to mix the two inputs. 21 | 22 | @related 23 | 24 | * [Volume Layer Merge|Node:vop/jparker--volumelayermerge] 25 | * [Volume Layer Shader|Node:vop/jparker--volumelayershader] 26 | * [Volume Layer Add Quantity|Node:vop/jparker--volumelayeraddquantity] 27 | * [Volume Layer Compute Lighting|Node:vop/jparker--volumelayercomputelighting] 28 | * [Volume Layer to Shading Layer|Node:vop/jparker--volumelayertoshadinglayer] 29 | * [Volume Layer Pack|Node:vop/jparker--volumelayerpack] 30 | * [Volume Layer Unpack|Node:vop/jparker--volumelayerunpack] 31 | * [Volume Layer Adjust Multiscatter|Node:vop/jparker--volumelayeradjustmultiscatter] 32 | -------------------------------------------------------------------------------- /houdini/volumelayers/help/nodes/vop/jparker--volumelayerpack.txt: -------------------------------------------------------------------------------- 1 | = Volume Layer Pack = 2 | 3 | """Combine standard Houdini VEX shader inputs and create a VolumeLayer struct output.""" 4 | 5 | @inputs 6 | F: 7 | BSDF component input 8 | 9 | extinction: 10 | Total extinction (density) input. You need to ensure that the BSDF input already has the correct albedo computed relative to the extinction, which is a sum of scattering+absorption. This value should be the unitless value before dPdZ is applied. 11 | 12 | Ce: 13 | Emission coefficient. This is the unitless value before dPdz is applied. 14 | 15 | @related 16 | 17 | * [Volume Layer Merge|Node:vop/jparker--volumelayermerge] 18 | * [Volume Layer Shader|Node:vop/jparker--volumelayershader] 19 | * [Volume Layer Mix|Node:vop/jparker--volumelayermix] 20 | * [Volume Layer Add Quantity|Node:vop/jparker--volumelayeraddquantity] 21 | * [Volume Layer Compute Lighting|Node:vop/jparker--volumelayercomputelighting] 22 | * [Volume Layer to Shading Layer|Node:vop/jparker--volumelayertoshadinglayer] 23 | * [Volume Layer Unpack|Node:vop/jparker--volumelayerunpack] 24 | * [Volume Layer Adjust Multiscatter|Node:vop/jparker--volumelayeradjustmultiscatter] 25 | -------------------------------------------------------------------------------- /houdini/volumelayers/help/nodes/vop/jparker--volumelayerspacetransform.txt: -------------------------------------------------------------------------------- 1 | = Volume Layer Space Transform = 2 | 3 | """ Scales density and emission to match space transform.""" 4 | 5 | @inputs 6 | 7 | volumelayer: 8 | Input volume layer to modify. 9 | 10 | @outputs 11 | 12 | volumelayer: 13 | Modified volume layer. 14 | 15 | @parameters 16 | 17 | From Space: 18 | #id: fromspace 19 | 20 | Shading manifold that input densities are assumed to be in. 21 | 22 | To Space: 23 | #id: tospace 24 | 25 | Target shading manifold to scale density and emission by. 26 | 27 | @related 28 | 29 | * [Volume Layer Merge|Node:vop/jparker--volumelayermerge] 30 | * [Volume Layer Shader|Node:vop/jparker--volumelayershader] 31 | * [Volume Layer Mix|Node:vop/jparker--volumelayermix] 32 | * [Volume Layer Add Quantity|Node:vop/jparker--volumelayeraddquantity] 33 | * [Volume Layer Compute Lighting|Node:vop/jparker--volumelayercomputelighting] 34 | * [Volume Layer to Shading Layer|Node:vop/jparker--volumelayertoshadinglayer] 35 | * [Volume Layer Unpack|Node:vop/jparker--volumelayerunpack] 36 | * [Volume Layer Pack|Node:vop/jparker--volumelayerpack] 37 | * [Volume Layer Adjust Multiscatter|Node:vop/jparker--volumelayeradjustmultiscatter] 38 | -------------------------------------------------------------------------------- /houdini/volumelayers/help/nodes/vop/jparker--volumelayeraddquantity.txt: -------------------------------------------------------------------------------- 1 | = Volume Layer Add Quantity = 2 | 3 | """Add a component property to an input VolumeLayer struct.""" 4 | 5 | == Overview == 6 | 7 | This operator takes a VolumeLayer struct as input and adds scattering, absorption or emission to it. 8 | 9 | @inputs 10 | volumelayer: 11 | VolumeLayer to modify 12 | 13 | @parameters 14 | 15 | Scattering: 16 | #id: scatter 17 | 18 | Scattering coefficient. Probability light is scattered by the material, ranging from zero to infinity. 19 | 20 | Absorption: 21 | #id: absorb 22 | 23 | Absorption coefficient. Probability light is absorbed by the material, ranging from zero to infinity. 24 | 25 | Emission: 26 | #id: emit 27 | 28 | Emission coefficient. Probability light is re-emitted by the material, ranging from zero to infinity. 29 | 30 | @related 31 | 32 | * [Volume Layer Merge|Node:vop/jparker--volumelayermerge] 33 | * [Volume Layer Shader|Node:vop/jparker--volumelayershader] 34 | * [Volume Layer Mix|Node:vop/jparker--volumelayermix] 35 | * [Volume Layer Compute Lighting|Node:vop/jparker--volumelayercomputelighting] 36 | * [Volume Layer to Shading Layer|Node:vop/jparker--volumelayertoshadinglayer] 37 | * [Volume Layer Pack|Node:vop/jparker--volumelayerpack] 38 | * [Volume Layer Unpack|Node:vop/jparker--volumelayerunpack] 39 | * [Volume Layer Adjust Multiscatter|Node:vop/jparker--volumelayeradjustmultiscatter] -------------------------------------------------------------------------------- /houdini/volumelayers/help/nodes/vop/jparker--scaleheightdensity.txt: -------------------------------------------------------------------------------- 1 | = Scale Height Density = 2 | 3 | """ Computes exponential density profile from altitude and scale height.""" 4 | 5 | == Overview == 6 | 7 | This operator generates a density profile that falls off exponentially from the zero altitude to infinity. Typical fog shaders in computer graphics are a type of this density behavior. 8 | 9 | As an example, in the context of atmospheric rendering, the atmosphere isn't uniform; it varies in terms of factors like temperature, density, and composition as you move upwards from the surface. Scale height is a way to quantify this change. It represents the vertical distance over which a particular property of the atmosphere decreases by a factor of e (approximately 2.71828), which is the base of natural logarithms. 10 | 11 | For more information on scale height, see: 12 | 13 | [Scale Height (Wikipedia)|https://en.wikipedia.org/wiki/Scale_height] 14 | 15 | @inputs 16 | 17 | altitude: 18 | On Earth, altitude above sea level. On rocky planets this is mean surface height. On gas giants this is the distance from the center of the planet at which the atmosphere equals one bar of pressure. 19 | 20 | h: 21 | Scale height value. This is the density halfway point: half of the integrated total density is below this altitude, and half is above. Smaller values will make the falloff sharper, and larger values will make it softer. 22 | 23 | @outputs 24 | 25 | density: 26 | Computed density value. 27 | 28 | -------------------------------------------------------------------------------- /houdini/volumelayers/help/nodes/vop/jparker--pbrttu2phase.txt: -------------------------------------------------------------------------------- 1 | = PBR Two-Term Ultraspherical Phase Function = 2 | 3 | """ Generates a scattering phase function BSDF that simulates interstellar dust scattering.""" 4 | 5 | == Overview == 6 | 7 | This operator implements the two-term ultraspherical phase function, which approximates scattering by dust grains in the interstellar medium. 8 | 9 | For more information see: 10 | 11 | [A new analytical scattering phase function for interstellar dust|https://arxiv.org/abs/2202.01607] 12 | 13 | Citation: 14 | 15 | A new analytical scattering phase function for interstellar dust 16 | Maarten Baes, Peter Camps, Anand Utsav Kapoor 17 | A&A 659 A149 (2022) 18 | DOI: 10.1051/0004-6361/202142437 19 | 20 | 21 | TIP: 22 | To apply physically meaningful values to the parameters, start by selecting one of the presets in the "bandpreset" parameter. 23 | 24 | 25 | @parameters 26 | 27 | Component Label: 28 | #id: label 29 | BSDF component label. 30 | 31 | Band Preset: 32 | #id: bandpreset 33 | Applies a preset for a specific electromagnetic frequency. 34 | 35 | Forward Phase: 36 | #id: g1 37 | Forward scattering phase. Larger values scatter more strongly forward. 38 | 39 | Backward Phase: 40 | #id: g2 41 | Backscattering phase. Lower values scatter more strongly back towards the viewer. 42 | 43 | Weight: 44 | #id: y 45 | How much to weight towards the forward or backward phase. A value of 1 weights the forward phase by 100%. 46 | 47 | @outputs 48 | 49 | f: 50 | BSDF 51 | -------------------------------------------------------------------------------- /houdini/volumelayers/help/nodes/vop/jparker--volumelayeradjustmultiscatter.txt: -------------------------------------------------------------------------------- 1 | = Volume Layer Add Quantity = 2 | 3 | """ Adjusts volume layer properties in indirect bounces. """ 4 | 5 | == Overview == 6 | 7 | This operator takes a VolumeLayer struct as input and modifies extinction and BSDF albedo in indirect bounces. Lowering the extinction and increasing the albedo can add more softness to volume lighting without increasing render time, as opposed to increasing the number of indirect bounces. 8 | 9 | @inputs 10 | volumelayer: 11 | VolumeLayer to modify 12 | 13 | @parameters 14 | 15 | Contribution Modifier: 16 | #id: contributionmodifier 17 | 18 | Multiply BSDF albedo by this amount for every indirect ray bounce. 19 | 20 | Extinction Modifier: 21 | #id: extinctionmodifier 22 | 23 | Multiply apparent extinction (density) by this amount for every indirect ray bounce. 24 | 25 | Modifier Start Level: 26 | #id: modifierstartlevel 27 | 28 | Minimum indirect bounce level to apply the contribution and extinction modifiers at. Zero means the first indirect bounce onwards is affected. 29 | 30 | @related 31 | 32 | * [Volume Layer Merge|Node:vop/jparker--volumelayermerge] 33 | * [Volume Layer Shader|Node:vop/jparker--volumelayershader] 34 | * [Volume Layer Mix|Node:vop/jparker--volumelayermix] 35 | * [Volume Layer Compute Lighting|Node:vop/jparker--volumelayercomputelighting] 36 | * [Volume Layer to Shading Layer|Node:vop/jparker--volumelayertoshadinglayer] 37 | * [Volume Layer Pack|Node:vop/jparker--volumelayerpack] 38 | * [Volume Layer Unpack|Node:vop/jparker--volumelayerunpack] 39 | * [Volume Layer Add Quantity|Node:vop/jparker--volumelayeraddquantity] 40 | -------------------------------------------------------------------------------- /houdini/volumelayers/vex/CVex/rayleigh_eval.vfl: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2023 Jon Parker 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | // Rayleigh Phase Function 26 | 27 | /*Citation 28 | 29 | Frisvad, J. R. (2011). Importance sampling the Rayleigh phase function. Optical Society of America. Journal A: 30 | Optics, Image Science, and Vision, 28(12), 2436-2441. https://doi.org/10.1364/JOSAA.28.002436 31 | */ 32 | 33 | #include "pbr.h" 34 | 35 | cvex rayleigh_eval( 36 | vector u = 0; 37 | vector v = 0; 38 | int bounces = 0; 39 | int reverse = 0; 40 | export vector refl = 0; 41 | export vector eval = 0; 42 | export float pdf = 0; 43 | 44 | int mybounces = 0; 45 | ) 46 | { 47 | if (bounces & mybounces) 48 | { 49 | float costheta = -dot(u, v); 50 | pdf = 0.375 * (1 + (costheta*costheta)); 51 | eval = pdf; 52 | refl = 1; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /houdini/volumelayers/help/nodes/vop/jparker--pbrapproxmie.txt: -------------------------------------------------------------------------------- 1 | = PBR Approximate Mie Phase Function = 2 | 3 | """ Generates a scattering phase function BSDF that simulates interstellar dust scattering.""" 4 | 5 | == Overview == 6 | 7 | This operator implements the Approximate Mie phase function, which models anisotropic scattering of droplets in a medium. This BSDF is useful when you want to model the appearance of clouds. 8 | 9 | The model is implemented as a mix between a Henyey-Greenstein phase function and a Draine phase function. For more information see: 10 | 11 | [An Approximate Mie Scattering Function for Fog and Cloud Rendering (NVIDIA)|https://research.nvidia.com/labs/rtr/approximate-mie/] 12 | 13 | 14 | @parameters 15 | 16 | Component Label: 17 | #id: label 18 | BSDF component label. 19 | 20 | Parameter Mode: 21 | #id: mode 22 | Which parameters to use do define the shape of the PSDF. "Droplet" is a fitting of the "aniso" parameters, using droplet size as input. 23 | 24 | Droplet Size: 25 | #id: dropletsize 26 | Average diameter, in micrometers, of the droplets that define the medium. Smaller droplets scatter light more evenly in all directions, while larger droplets scatter light mostly in the forward direction away from the light. Values above 50 micrometers are ill-defined by the model, so the parameter range is clamped to this amount. 27 | 28 | Primary Anisotropy: 29 | #id: ghg 30 | Henyey Greenstein scattering phase. Larger values scatter more strongly forward. 31 | 32 | Secondary Anisotropy: 33 | #id: gd 34 | Draine scattering phase. Lower values scatter more strongly back towards the viewer. 35 | 36 | Secondary Weight: 37 | #id: weight 38 | Blend value between primary and secondary scattering. 39 | 40 | Secondary Shape: 41 | #id: shape 42 | Shaping of the Draine phase function. Larger values will bias the scattering towards both the forward and backward directions, while reducing the visible contribution at right angles to the viewer's viewing direction of the light. 43 | 44 | @outputs 45 | 46 | f: 47 | BSDF 48 | -------------------------------------------------------------------------------- /houdini/volumelayers/vex/CVex/draine_eval.vfl: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2023 Jon Parker 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | /* 26 | Draine BSDF evaluation function derived from GLSL code provided here: 27 | https://research.nvidia.com/labs/rtr/approximate-mie/ 28 | 29 | Citation: 30 | [Jendersie and d'Eon 2023] 31 | SIGGRAPH 2023 Talks 32 | https://doi.org/10.1145/3587421.3595409 33 | */ 34 | 35 | float eval_draine_pdf(float u; float g; float a) 36 | { 37 | float g2 = g*g; 38 | float temp = 1 + g2 - (g+g) * u; 39 | temp *= sqrt(temp); 40 | return ((1 - g2) / temp) * ((1 + a * u*u) / (1 + a * (1 + (g2+g2)) / 3)); 41 | } 42 | 43 | 44 | cvex draine_eval( 45 | vector u = 0; 46 | vector v = 0; 47 | int bounces = 0; 48 | int reverse = 0; 49 | export vector refl = 0; 50 | export vector eval = 0; 51 | export float pdf = 0; 52 | 53 | int mybounces = 0; 54 | float phase = 0; 55 | float alpha = 0 // 0 - ~5 or 6 56 | ) 57 | { 58 | if (bounces & mybounces) 59 | { 60 | float a = max(alpha, 0.0); 61 | float g = clamp(phase, -.9999999, .9999999); 62 | float g2 = g*g; 63 | float costheta = -dot(u, v); 64 | 65 | pdf = eval_draine_pdf(costheta, g, a); 66 | 67 | // vs. 1 / 4pi from the paper since Houdini's system normalizes it externally 68 | pdf *= 0.5; 69 | 70 | eval = pdf; 71 | refl = 1; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /houdini/volumelayers/vex/CVex/rayleigh_sample.vfl: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2023 Jon Parker 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | // Rayleigh Phase Function 26 | 27 | /*Citation 28 | 29 | Frisvad, J. R. (2011). Importance sampling the Rayleigh phase function. Optical Society of America. Journal A: 30 | Optics, Image Science, and Vision, 28(12), 2436-2441. https://doi.org/10.1364/JOSAA.28.002436 31 | */ 32 | #include "math.h" 33 | #include "pbr.h" 34 | 35 | // Use the direct sampling method in the paper 36 | // TODO: try out rejection sampling for an exercise 37 | cvex rayleigh_sample( 38 | export int flags = 0; 39 | 40 | vector u = 0; 41 | float sx = 0; 42 | float sy = 0; 43 | int bounces = 0; 44 | 45 | export vector refl = 1; 46 | export vector v = 0; 47 | export int bouncetype = 0; 48 | export float pdf = 0; 49 | 50 | int mybounces = 0; 51 | ) 52 | { 53 | if (bounces & mybounces) 54 | { 55 | float x2_1 = 2 * sy - 1; 56 | float temp = -pow(2 * x2_1 + sqrt(4 * (x2_1 * x2_1) + 1), 1./3); 57 | float y = temp - 1. / temp; 58 | 59 | pdf = 0.75 * (1 + (y*y)); 60 | pdf *= 0.5; 61 | 62 | bouncetype = mybounces; 63 | 64 | float z = y; 65 | y = 0.5 * y + 0.5; 66 | float w = 2*sqrt(y*(1-y)); 67 | v = set(w*cos(2*PI*sx), w*sin(2*PI*sx), z); 68 | 69 | vector framex, framey; 70 | makebasis(framex, framey, u, {1,0,0}); 71 | 72 | v = v.x*framex + v.y*framey - v.z*u; 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /houdini/volumelayers/vex/include/ttu2.h: -------------------------------------------------------------------------------- 1 | #ifndef __TTU2 2 | #define __TTU2 3 | /* 4 | MIT License 5 | 6 | Copyright (c) 2023 Jon Parker 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | // two-term ultraspherical-2 phase function 28 | 29 | /*Citation 30 | 31 | A new analytical scattering phase function for interstellar dust 32 | Maarten Baes, Peter Camps, Anand Utsav Kapoor 33 | A&A 659 A149 (2022) 34 | DOI: 10.1051/0004-6361/202142437 35 | */ 36 | 37 | /* 38 | From paper: 39 | "Model parameters of the best-fitting TTU2 phase functions for the BARE-GR-S dust model 40 | at the central wavelengths of a number of standard broadband filters." 41 | 42 | Band λ g1 g2 γ 43 | [μm] 44 | FUV 0.154 0.764 −0.016 0.950 45 | NUV 0.230 0.670 −0.010 0.792 46 | u 0.356 0.545 −0.048 0.841 47 | g 0.470 0.449 −0.109 0.882 48 | r 0.618 0.361 −0.308 0.952 49 | i 0.749 0.320 −0.370 0.967 50 | z 0.895 0.288 −0.327 0.960 51 | J 1.239 0.262 −0.274 0.846 52 | H 1.649 0.259 −0.240 0.643 53 | Ks 2.164 0.254 −0.241 0.583 54 | W1 3.390 0.248 −0.245 0.549 55 | W2 4.641 0.247 −0.246 0.526 56 | */ 57 | 58 | 59 | bsdf ttu2_bsdf(const float g1; const float g2; const float weight; const string label) 60 | { 61 | return cvex_bsdf("ttu2_eval", "ttu2_sample", "label", label, "phase1", g1, "phase2", g2, "weight", weight); 62 | } 63 | 64 | bsdf ttu2_bsdf(const float g1; const float g2; const float weight) 65 | { 66 | return cvex_bsdf("ttu2_eval", "ttu2_sample", "label", "volume", "phase1", g1, "phase2", g2, "weight", weight); 67 | } 68 | 69 | 70 | #endif -------------------------------------------------------------------------------- /houdini/volumelayers/vex/CVex/ttu2_eval.vfl: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2023 Jon Parker 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | // two-term ultraspherical-2 phase function 26 | 27 | /*Citation 28 | 29 | A new analytical scattering phase function for interstellar dust 30 | Maarten Baes, Peter Camps, Anand Utsav Kapoor 31 | A&A 659 A149 (2022) 32 | DOI: 10.1051/0004-6361/202142437 33 | */ 34 | 35 | /* 36 | From paper: 37 | "Model parameters of the best-fitting TTU2 phase functions for the BARE-GR-S dust model 38 | at the central wavelengths of a number of standard broadband filters." 39 | 40 | Band λ g1 g2 γ 41 | [μm] 42 | FUV 0.154 0.764 −0.016 0.950 43 | NUV 0.230 0.670 −0.010 0.792 44 | u 0.356 0.545 −0.048 0.841 45 | g 0.470 0.449 −0.109 0.882 46 | r 0.618 0.361 −0.308 0.952 47 | i 0.749 0.320 −0.370 0.967 48 | z 0.895 0.288 −0.327 0.960 49 | J 1.239 0.262 −0.274 0.846 50 | H 1.649 0.259 −0.240 0.643 51 | Ks 2.164 0.254 −0.241 0.583 52 | W1 3.390 0.248 −0.245 0.549 53 | W2 4.641 0.247 −0.246 0.526 54 | */ 55 | 56 | #include "pbr.h" 57 | 58 | float ultraspherical_eval_pdf(const float phase; const float costheta) 59 | { 60 | float g = clamp(phase, -1, 1); 61 | float g2 = g*g; 62 | 63 | float temp = 1 + g2 - 2 * g * costheta; 64 | return (1 - g2) * (1 - g2) / (temp*temp); 65 | } 66 | 67 | cvex ttu2_eval( 68 | vector u = 0; 69 | vector v = 0; 70 | int bounces = 0; 71 | int reverse = 0; 72 | export vector refl = 0; 73 | export vector eval = 0; 74 | export float pdf = 0; 75 | 76 | int mybounces = 0; 77 | float phase1 = 0; 78 | float phase2 = 0; 79 | float weight = 0.5; 80 | ) 81 | { 82 | if (bounces & mybounces) 83 | { 84 | float costheta = -dot(u, v); 85 | float g_1 = max(phase1, 0); 86 | float g_2 = min(phase2, 0); 87 | 88 | pdf = weight * ultraspherical_eval_pdf(g_1, costheta) + (1 - weight) * ultraspherical_eval_pdf(g_2, costheta); 89 | 90 | pdf *= 0.5; 91 | eval = pdf; 92 | refl = 1; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /houdini/volumelayers/vex/CVex/ttu2_sample.vfl: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2023 Jon Parker 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | // two-term ultraspherical-2 phase function 26 | 27 | /*Citation 28 | 29 | A new analytical scattering phase function for interstellar dust 30 | Maarten Baes, Peter Camps, Anand Utsav Kapoor 31 | A&A 659 A149 (2022) 32 | DOI: 10.1051/0004-6361/202142437 33 | */ 34 | 35 | /* 36 | From paper: 37 | "Model parameters of the best-fitting TTU2 phase functions for the BARE-GR-S dust model 38 | at the central wavelengths of a number of standard broadband filters." 39 | 40 | Band λ g1 g2 γ 41 | [μm] 42 | FUV 0.154 0.764 −0.016 0.950 43 | NUV 0.230 0.670 −0.010 0.792 44 | u 0.356 0.545 −0.048 0.841 45 | g 0.470 0.449 −0.109 0.882 46 | r 0.618 0.361 −0.308 0.952 47 | i 0.749 0.320 −0.370 0.967 48 | z 0.895 0.288 −0.327 0.960 49 | J 1.239 0.262 −0.274 0.846 50 | H 1.649 0.259 −0.240 0.643 51 | Ks 2.164 0.254 −0.241 0.583 52 | W1 3.390 0.248 −0.245 0.549 53 | W2 4.641 0.247 −0.246 0.526 54 | */ 55 | 56 | #include "math.h" 57 | #include "pbr.h" 58 | 59 | float ultraspherical_sample_cos(const float x; const float g) 60 | { 61 | float oneplusg2 = (1 + g) * (1 + g); 62 | return (oneplusg2 - 2 * x * (1 + g*g)) / (oneplusg2 - 4 * g * x); 63 | } 64 | 65 | float ultraspherical_sample_pdf(const float phase; const float costheta) 66 | { 67 | float g = clamp(phase, -1, 1); 68 | float g2 = g*g; 69 | 70 | float temp = 1 + g2 - 2 * g * costheta; 71 | return (1 - g2) * (1 - g2) / (temp*temp); 72 | } 73 | 74 | cvex ttu2_sample( 75 | export int flags = 0; 76 | 77 | vector u = 0; 78 | float sx = 0; 79 | float sy = 0; 80 | int bounces = 0; 81 | 82 | export vector refl = 1; 83 | export vector v = 0; 84 | export int bouncetype = 0; 85 | export float pdf = 0; 86 | 87 | int mybounces = 0; 88 | float phase1 = 0; 89 | float phase2 = 0; 90 | float weight = 0.5; 91 | ) 92 | { 93 | if (bounces & mybounces) 94 | { 95 | float g = sy < weight ? max(phase1, 0) : min(phase2, 0); 96 | g = clamp(g, -1, 1); 97 | float g2 = g*g; 98 | 99 | float X = sy < weight ? sy/weight : (1-sy)/(1-weight); 100 | 101 | float y = ultraspherical_sample_cos(X, g); 102 | pdf = ultraspherical_sample_pdf(g, y); 103 | pdf *= 0.5; 104 | 105 | bouncetype = mybounces; 106 | 107 | float z = y; 108 | y = 0.5 * y + 0.5; 109 | float w = 2*sqrt(y*(1-y)); 110 | v = set(w*cos(2*PI*sx), w*sin(2*PI*sx), z); 111 | 112 | vector framex, framey; 113 | makebasis(framex, framey, u, {1,0,0}); 114 | 115 | v = v.x*framex + v.y*framey - v.z*u; 116 | } 117 | } 118 | 119 | -------------------------------------------------------------------------------- /houdini/volumelayers/vex/CVex/draine_sample.vfl: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2023 Jon Parker 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | /* 26 | Draine BSDF sampling function derived from GLSL code provided here: 27 | https://research.nvidia.com/labs/rtr/approximate-mie/ 28 | 29 | Citation: 30 | [Jendersie and d'Eon 2023] 31 | SIGGRAPH 2023 Talks 32 | https://doi.org/10.1145/3587421.3595409 33 | */ 34 | 35 | #include "math.h" 36 | 37 | float sample_draine_cos(float xi; float g; float a) 38 | { 39 | float g2 = g * g; 40 | float g3 = g * g2; 41 | float g4 = g2 * g2; 42 | float g6 = g2 * g4; 43 | float pgp1_2 = (1 + g2) * (1 + g2); 44 | float T1 = (-1 + g2) * (4 * g2 + a * pgp1_2); 45 | float T1a = -a + a * g4; 46 | float T1a3 = T1a * T1a * T1a; 47 | float T2 = -1296 * (-1 + g2) * (a - a * g2) * (T1a) * (4 * g2 + a * pgp1_2); 48 | float T3 = 3 * g2 * (1 + g * (-1 + 2 * xi)) + a * (2 + g2 + g3 * (1 + 2 * g2) * (-1 + 2 * xi)); 49 | float T4a = 432 * T1a3 + T2 + 432 * (a - a * g2) * T3 * T3; 50 | float T4b = -144 * a * g2 + 288 * a * g4 - 144 * a * g6; 51 | float T4b3 = T4b * T4b * T4b; 52 | float T4 = T4a + sqrt(-4 * T4b3 + T4a * T4a); 53 | float T4p3 = pow(T4, 1.0 / 3.0); 54 | float T6 = (2 * T1a + (48 * pow(2, 1.0 / 3.0) * 55 | (-(a * g2) + 2 * a * g4 - a * g6)) / T4p3 + T4p3 / (3. * pow(2, 1.0 / 3.0))) / (a - a * g2); 56 | float T5 = 6 * (1 + g2) + T6; 57 | return (1 + g2 - pow(-0.5 * sqrt(T5) + sqrt(6 * (1 + g2) - (8 * T3) / (a * (-1 + g2) * sqrt(T5)) - T6) / 2., 2)) / (2. * g); 58 | } 59 | 60 | // identical to eval_draine_pdf in draine_eval.vfl 61 | float sample_draine_pdf(float u; float g; float a) 62 | { 63 | float g2 = g*g; 64 | float temp = 1 + g2 - (g+g) * u; 65 | temp *= sqrt(temp); 66 | return ((1 - g2) / temp) * ((1 + a * u*u) / (1 + a * (1 + (g2+g2)) / 3)); 67 | } 68 | 69 | cvex draine_sample( 70 | export int flags = 0; 71 | 72 | vector u = 0; 73 | float sx = 0; 74 | float sy = 0; 75 | int bounces = 0; 76 | 77 | export vector refl = 1; 78 | export vector v = 0; 79 | export int bouncetype = 0; 80 | export float pdf = 0; 81 | 82 | int mybounces = 0; 83 | float phase = 0; 84 | float alpha = 0 85 | ) 86 | { 87 | if (bounces & mybounces) 88 | { 89 | float g = clamp(phase, -.9999999, .9999999); 90 | float a = max(alpha, 0); 91 | 92 | float y = sample_draine_cos(sy, g, a); 93 | pdf = sample_draine_pdf(y, g, a); 94 | pdf *= 0.5; 95 | 96 | bouncetype = mybounces; 97 | 98 | float z = y; 99 | y = 0.5 * y + 0.5; 100 | float w = 2*sqrt(y*(1-y)); 101 | v = set(w*cos(2*PI*sx), w*sin(2*PI*sx), z); 102 | 103 | vector framex, framey; 104 | makebasis(framex, framey, u, {1,0,0}); 105 | 106 | v = v.x*framex + v.y*framey - v.z*u; 107 | } 108 | } 109 | 110 | -------------------------------------------------------------------------------- /houdini/volumelayers/help/nodes/vop/jparker--volumelayer.txt: -------------------------------------------------------------------------------- 1 | = Volume Layer Shader = 2 | 3 | #icon: path/to/icon 4 | 5 | """Construct a volume layer shader.""" 6 | 7 | == Overview == 8 | 9 | This operator creates a VolumeLayer base shader that can be used in a VOP network to correctly and efficiently combine different volume mediums. 10 | 11 | Houdini's own shading layer compositing nodes do not combine volume shaders in a physically correct way. For example: 12 | - In the standard volume shader nodes that are included with Houdini, opacity is computed within the VOP before being passed to the output, which when combined with the standard shading layer composite nodes results in incorrect shading. To calculate opacity correctly, density from all input volume shaders must be *added* together before opacity is computed. 13 | - When combining volume shaders, the BSDF contribution of each input must be weighted by the their relative extinction values, which is not possible when opacity is pre-calculated per-shading layer. 14 | 15 | To correct these problems, nodes that work with VolumeLayer structs combine properties prior to computing opacity. Modifying shader properties by wiring VolumeLayer struct-based nodes directly together maintains the accuracy of the shader network operations. 16 | 17 | Think of this node as a specific volumetric medium. That medium has a density, and can interact with light by scattering it in a certain direction, absorbing it, or emit light via some other energetic process. 18 | 19 | TIP: 20 | - Add a [Volume Layer Compute Lighting|jparker--volumelayercomputelighting] node to the VOP network and wire the VolumeLayer output into it to extract the final F, Ce, Cd and Of output values. 21 | - Use the [Volume Layer Merge|jparker--volumelayermerge] node to combine separate Volume Layer Shader nodes in a physically correct way. 22 | - If you need more control, use the [Volume Layer Mix|jparker--volumelayermix] or [Volume Layer Add Quantity|jparker--volumelayeraddquantity] nodes to combine volume layer properties in other ways. 23 | 24 | @inputs 25 | density: 26 | Base material density, float. Scattering, absorption and emission are scaled by this value. If nothing is connected, the shader will use the bound "density" field of the volume, otherwise is zero. 27 | 28 | F: 29 | Override the default Henyey-Greenstein phase function BSDF. One reason to use this input is if you need to combine multiple BSDFs to achieve more complex scattering directions. For example, a haze that has a very focused forward scattering peak that is mixed with a more general scattering direction. 30 | 31 | @parameters 32 | 33 | Density Field: 34 | #id: densityfield 35 | 36 | When density is not connected, default volume field to use as density value. 37 | 38 | Scattering: 39 | #id: scatter 40 | 41 | Scattering coefficient. Probability light is scattered by the material, ranging from zero to infinity, multiplied by density. 42 | 43 | Scattering Direction: 44 | #id: phase 45 | 46 | Anisotropic direction bias. How strongly light is scattered back towards or away from the light source direction. Range is (-1, 1). 47 | 48 | Label: 49 | #id: label 50 | 51 | Shading BSDF component label. 52 | 53 | Absorption: 54 | #id: absorb 55 | 56 | Absorption coefficient. Probability light is absorbed by the material, ranging from zero to infinity, multiplied by density. 57 | 58 | Emission: 59 | #id: emit 60 | 61 | Emission coefficient. Probability light is re-emitted by the material, ranging from zero to infinity, multiplied by density. 62 | 63 | @related 64 | 65 | * [Volume Layer Merge|Node:vop/jparker--volumelayermerge] 66 | * [Volume Layer Mix|Node:vop/jparker--volumelayermix] 67 | * [Volume Layer Add Quantity|Node:vop/jparker--volumelayeraddquantity] 68 | * [Volume Layer Compute Lighting|Node:vop/jparker--volumelayercomputelighting] 69 | * [Volume Layer to Shading Layer|Node:vop/jparker--volumelayertoshadinglayer] 70 | * [Volume Layer Pack|Node:vop/jparker--volumelayerpack] 71 | * [Volume Layer Unpack|Node:vop/jparker--volumelayerunpack] 72 | * [Volume Layer Flatten|Node:vop/jparker--volumelayerflatten] 73 | * [Volume Layer Adjust Multiscatter|Node:vop/jparker--volumelayeradjustmultiscatter] 74 | -------------------------------------------------------------------------------- /houdini/volumelayers/vex/include/volumelayer.h: -------------------------------------------------------------------------------- 1 | #ifndef __GUARD__VOLUME_LAYER__ 2 | #define __GUARD__VOLUME_LAYER__ 3 | /* 4 | MIT License 5 | 6 | Copyright (c) 2023 Jon Parker 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | /* 28 | Volume layer struct. 29 | Layering volume shaders is NOT like layering surface shaders and the struct below is a fix for that. 30 | */ 31 | 32 | struct VolumeLayer 33 | { 34 | bsdf F ; 35 | vector density ; 36 | vector Ce ; 37 | } 38 | 39 | // Construct a volume layer. f is assumed to have an unmodified albedo... 40 | VolumeLayer buildVolumeLayer( 41 | bsdf f; 42 | vector absorb; 43 | vector scatter; 44 | vector emit; 45 | ) 46 | { 47 | vector extinction = absorb + scatter; 48 | vector albedo = scatter / extinction; 49 | 50 | return VolumeLayer(f * albedo, extinction, emit); 51 | } 52 | 53 | VolumeLayer buildVolumeLayer( 54 | float phase; 55 | vector absorb; 56 | vector scatter; 57 | vector emit; 58 | string label; 59 | ) 60 | { 61 | bsdf f; 62 | if (phase == 0) 63 | f = isotropic("label", label); 64 | else 65 | f = henyeygreenstein(phase, "label", label); 66 | 67 | return buildVolumeLayer(f, absorb, scatter, emit); 68 | } 69 | 70 | // Extract volume properties that are used as inputs to the "buildVolumeLayer" function. 71 | void extractVolumeLayerProperties( 72 | const VolumeLayer layer; 73 | export bsdf f; 74 | export vector scatter; 75 | export vector absorb; 76 | export vector emit; 77 | ) 78 | { 79 | vector albedo = albedo(layer.F); 80 | // anything in the albedo over 1.0 is extra emissive energy in the bsdf 81 | vector f_emit = (max(albedo - 1, 0) + 1); 82 | f = layer.F * (1. / albedo) * f_emit; 83 | scatter = layer.density * albedo; 84 | absorb = layer.density - scatter; 85 | emit = layer.Ce; 86 | } 87 | 88 | VolumeLayer volumeLayerMerge( 89 | const VolumeLayer a; 90 | const VolumeLayer b; 91 | ) 92 | { 93 | vector density = a.density + b.density; 94 | bsdf f = (a.F * (a.density / density)) + (b.F * (b.density / density)); 95 | vector emit = a.Ce + b.Ce; 96 | return VolumeLayer(f, density, emit); 97 | } 98 | 99 | 100 | VolumeLayer volumeLayerMix( 101 | const VolumeLayer a; 102 | const VolumeLayer b; 103 | float density_mix; 104 | float F_mix; 105 | float Ce_mix; 106 | ) 107 | { 108 | vector density = a.density * (1. - density_mix) + b.density * density_mix; 109 | bsdf f = (a.F * (a.density / density) * (1. - F_mix)) + (b.F * (b.density / density) * F_mix); 110 | vector emit = a.Ce * (1. - Ce_mix) + b.Ce * Ce_mix; 111 | return VolumeLayer(f, density, emit); 112 | } 113 | 114 | VolumeLayer volumeLayerMix( 115 | const VolumeLayer a; 116 | const VolumeLayer b; 117 | float mix; 118 | ) 119 | { 120 | return volumeLayerMix(a, b, mix, mix, mix); 121 | } 122 | 123 | /* 124 | struct VolumeLayerArray 125 | { 126 | bsdf F[] ; 127 | vector density[]; 128 | vector Ce[] ; 129 | } 130 | 131 | VolumeLayer volumeLayerMerge( 132 | VolumeLayerArray layers; 133 | ) 134 | { 135 | VolumeLayer out = VolumeLayer(bsdf(), vector(0.), vector(0.)); 136 | foreach(int i=0; i Earth 1 69 | Earth 2 Earth 2 70 | 71 | 72 | #### Mars 73 | 74 | The render of Mars below uses three **`volumelayershader`** VOP nodes to model the atmosphere. Like the Earth render above, one struct models blue Rayleigh scattering; however, the density of the atmosphere of Mars is only 5% that of Earth at sea level, so the blue scattering is nearly invisibly. The second **`volumelayershader`** node models the effect of dust in the atmosphere. The dust is the red of the Martian surface, which is forward scattering, mostly red, and slightly absorbing of green and blue colors. A third **`volumelayershader`** is also combined; this also models dust, but is a thicker layer lying in the low areas, such as the large canyon Valles Marinaris seen towards the center of the sphere. 75 | 76 | Again, the thickness has been exagerrated to show the effect. 77 | 78 | Here we see the strong foward scattering of the dust as the crescent edge brightens considerably: 79 | 80 | Mars 1 Mars 3 81 | 82 | As we move toward the sun's POV, the bright glow around the edge is diminished because most of the light travels away from us: 83 | 84 | Mars Full Mars 2 85 | 86 | 87 | ### What about MaterialX and XPU? 88 | Because the VOP nodes in this toolset are VEX language VOPs, they will not work in Karma's XPU rendering mode. 89 | 90 | MaterialX has types that can theoretically reproduce the functionality of the `VolumeLayer` tools. However, as of Houdini 19.5, there are some limitations that make exact reproduction impossible. 91 | 92 | ## Licensing 93 | jpVolumeLayers is (c) Copyright Jon Parker. 94 | 95 | See [LICENSE](LICENSE) 96 | --------------------------------------------------------------------------------