docs: First stab at ReadTheDocs (#1736)

Convert the LaTeX docs to Sphinx + Myst Markdown extension

I think this is in decent shape. It's going to need a lot of thorough
proofreading to ensure that thing got lost or mangled on the way from
the original docs. I suspect we will have several follow-up PRs to fix
thing.

After we're reasonably happy with it, we'll eventually remove the
.tex and the pdf.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
This commit is contained in:
Larry Gritz
2023-10-05 12:10:57 -07:00
committed by GitHub
parent 9636c8c66c
commit 0d4c343759
22 changed files with 7921 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
# .readthedocs.yml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the OS, Python version and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.11"
# Build documentation with Sphinx
sphinx:
configuration: src/doc/conf.py
# Optionally build your docs in additional formats such as PDF and ePub
formats:
- pdf
- htmlzip
# Optionally set the version of Python and requirements required to build your docs
python:
install:
- requirements: src/doc/requirements.txt
+2556
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+32
View File
@@ -30,3 +30,35 @@ clean:
.PHONY: clean
doxygen:
echo "make doxygen TBD"
doxygen Doxyfile
touch doxygen.turd
doxygen.turd: doxygen
doxygenclean:
cmake -E remove_directory ../../build/doxygen
cmake -E remove doxygen.turd
cmake -E remove_directory ../../build/sphinx
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SOURCEDIR = .
SPHINXBUILDDIR = ../../build/sphinx
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
sphinx : Makefile conf.py
# @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(SPHINXBUILDDIR)" $(SPHINXOPTS) $(O)
$(SPHINXBUILD) -b html "$(SOURCEDIR)" "$(SPHINXBUILDDIR)" $(SPHINXOPTS)
sphinxpdf : Makefile conf.py
# @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(SPHINXBUILDDIR)" $(SPHINXOPTS) $(O)
$(SPHINXBUILD) -b latex "$(SOURCEDIR)" "$(SPHINXBUILDDIR)/latex" $(SPHINXOPTS)
$(MAKE) -C $(SPHINXBUILDDIR)/latex all-pdf
# $(SPHINXBUILD) -b latexpdf "$(SOURCEDIR)" "$(SPHINXBUILDDIR)/latex" $(SPHINXOPTS)
+307
View File
@@ -0,0 +1,307 @@
<!--
Copyright Contributors to the Open Shading Language project.
SPDX-License-Identifier: CC-BY-4.0
-->
(chap-bigpicture=)
# The Big Picture
This chapter attempts to lay out the major concepts of OSL,
define key nomenclature, and sketch out how individual shaders fit
together in the context of a renderer as a whole.
<!--
Other than the background material of this chapter, the rest of this
specification deals strictly with the language itself. In the future,
there will be separate (shorter) documents explaining in detail the use
of the language compiler, the renderer-side issues, the library and APIs
for how a renderer actually causes shaders to be evaluated, and so on.
-->
#### A shader is code that performs a discrete task
A shader is a program, with inputs and outputs, that performs a specific
task when rendering a scene, such as determining the appearance behavior
of a material or light. The program code is written in OSL, the
specification of which comprises this document.
For example, here is a simple `gamma` shader that performs
simple gamma correction on is `Cin` input, storing the result
in its output `Cout`:
```{image} Figures/shaderschematic.png
:width: 6.0in
```
The shader's inputs and outputs are called *shader parameters*.
Parameters have default values, specified in the shader code, but may
also be given new values by the renderer at runtime.
#### Shader instances
A particular shader may be used many times in a scene, on different
objects or as different layers in a shader group. Each separate use of
a shader is called a *shader instance*. Although all instances of
a shader are comprised of the same program code, each instance may
override any or all of its default parameter values with its own set of
*instance values*.
Below is a schematic showing a `gamma` instance with the `gam` parameter
overridden with an instance-specific value of `2.2`.
```{image} Figures/instanceschematic.png
:width: 200px
```
#### Shader groups, layers, and connections
A *shader group* is an ordered sequence of individual shaders called *layers*
that are executed in turn. Output parameters of an earlier-executed layer may
be *connected* to an input parameter of a later-executed layer. This connected
network of layers is sometimes called a *shader network* or a *shader DAG*
(directed acyclic graph). Of course, it is fine for the shader group to
consist of a single shader layer.
Below is a schematic showing how several shader instances may be
connected to form a shader group.
```{image} Figures/groupschematic.png
:width: 6.0in
```
And here is sample pseudo-code shows how the above network may be assembled
using an API in the renderer [^rendererapi]:
```
ShaderGroupBegin ()
Shader ("texturemap", /* shader name */
"tex1", /* layer name */
"string name", "rings.tx") /* instance variable */
Shader ("texturemap", "tex2", "string name", "grain.tx")
Shader ("gamma", "gam1", "float gam", 2.2)
Shader ("gamma", "gam2", "float gam", 1)
Shader ("wood", "wood1")
ConnectShaders ("tex1", /* layer name A */
"Cout", /* an output parameter of A */
"gam1", /* layer name B */
"Cin") /* Connect this layer of B to A's Cout */
ConnectShaders ("tex2", "Cout", "gam2", "Cin")
ConnectShaders ("gam1", "Cout", "wood1", "rings")
ConnectShaders ("gam2", "Cout", "wood1", "grain")
ShaderGroupEnd ()
```
Or, expressed as serialized text (as detailed in Chapter [](chap-shader-groups):
param string name "rings.tx" ;
shader "texturemap" "tex1" ;
param string name "grain.tx" ;
shader "texturemap" "tex2" ;
param float gam 2.2 ;
shader "gamma" "gam1" ;
param float gam 1.0 ;
shader "gamma" "gam2" ;
shader "wood" "wood1" ;
connect tex1.Cout gam1.Cin ;
connect tex2.Cout gam2.Cin ;
connect gam1.Cout wood1.rings ;
connect gam2.Cout wood1.grain ;
The rules for which data types may be connected are generally the same as
the rules determining which variables may be assigned to each other in OSL
source code:
* `source` and `dest` are the same data type.
* `source` and `dest` are both *triples* (`color`, `point`,
`vector`, or `normal`), even if they are not the same kind of triple.
* `source` is an `int` and `dest` is a `float`.
* `source` is a `float` or `int` and `dest` is a
*triple* (the scalar value will be replicated for all three components
of the triple).
* `source` is a single component of an aggregate type (e.g. one
channel of a `color`) and `dest` is a `float` (or vice versa).
#### Geometric primitives
The *scene* consists of primarily of geometric primitives,
light sources, and cameras.
*Geometric primitives* are shapes such as NURBS, subdivision surfaces,
polygons, and curves. The exact set of supported primitives may vary
from renderer to renderer.
Each geometric primitive carries around a set of named *primitive
variables* (also sometimes called *interpolated values* or
*user data*). Nearly all shape types will have, among their primitive
variables, control point positions that, when interpolated, actually
designate the shape. Some shapes will also allow the specification of
normals or other shape-specific data. Arbitrary user data may also be
attached to a shape as primitive variables. Primitive variables may be
interpolated in a variety of ways: one constant value per primitive, one
constant value per face, or per-vertex values that are interpolated
across faces in various ways.
If a shader input parameter's name and type match the name and type
of a primitive variable on the object (and that input parameters is
not already explicitly connected to another layer's output), the
interpolated primitive variable will override the instance value or
default.
#### Attribute state and shader assignments
Every geometric primitive has a collection of *attributes* (sometimes
called the *graphics state*) that includes its transformation
matrix, the list of which lights illuminate it, whether it is one-sided
or two-sided, shader assignments, etc. There may also be a long list of
renderer-specific or user-designated attributes associated with each
object. A particular attribute state may be shared among many geometric
primitives.
The attribute state also includes shader assignments --- the shaders or
shader groups for each of several *shader uses*, such as surface
shaders that designate how light reflects or emits from each point on a shape,
displacement shaders that can add fine detail to the shape on a
point-by-point basis, and volume shaders that describe how light is
scattered within a region of space. A particular renderer may have
additional shader types that it supports.
#### Shader execution state: parameter binding and global variables
When the body of code of an individual shader is about to execute, all
its parameters are *bound* --- that is, take on specific values
(from connections from other layers, interpolated primitive variables,
instance values, or defaults, in that order).
Certain state about the position on the surface where the shading is
being run is stored in so-called *global variables*. This includes
such useful data as the 3D coordinates of the point being shaded, the
surface normal and tangents at that point, etc.
Additionally, the shader may query other information about other
elements of the attribute state attached to the primitive, and
information about the renderer as a whole (rendering options, etc.).
#### Surface and volume shaders compute closures
Surface shaders (and volume shaders) do not by themselves compute the
final color of light emanating from the surface (or along a volume).
Rather, they compute a *closure*, which is a symbolic representation
describing the appearance of the surface, that may be more fully
evaluated later. This is in effect a parameterized formula, in which
some inputs have definite numeric values, but others may depend on
quantities not yet known (such as the direction from which the surface
is being viewed, and the amount of light from each source that is
arriving at the surface).
For example, a surface shader may compute its result like this:
color paint = texture ("file.tx", u, v);
Ci = paint * diffuse (N);
In this example, the variable `paint` will take on a specific numeric
value (by looking up from a texture map). But the `diffuse()` function
returns a `color closure`, not a definite numeric `color`. The output
variable `Ci` that represents the appearance of the surface is also a `color
closure`, whose numeric value is not known yet, except that it will be the
product of `paint`` and a Lambertian reflectance.
```{image} Figures/shaderexecschematic.png
```
The closures output by surface and volume shaders can do a number of
interesting things that a mere number cannot:
* Evaluate: given input and output light directions, compute the
proportion of light propagating from input to output.
* Sample: given just an input (or output) direction, choose a
scattering direction with a probability distribution that is
proportional to the amount of light that will end up going in various
directions.
* Integrate: given all lights and a view direction, compute
the total amount of light leaving the surface in the view direction.
* Recompute: given changes only to lights (or only to one light),
recompute the integrated result without recomputing other lights or
any of the calculations that went into assembling constants in the
closure (such as texture lookups, noise functions, etc.).
<!--
At present, we are assuming that the primitive closure functions (such
as `diffuse`, `ward`, `cooktorrance`, etc.) are all built
into the renderer, or implemented as renderer plugins. At a later time,
possibly in a later draft or maybe not until a truly later version of
the spec, we will fully spec it out so that closure primitive functions
may be written in OSL. But I fear that if we do it too soon,
we'll screw it up. But, yes, the eventual goal is for you to be able to
write these primitive functions in the language itself.
-->
#### Integrators
The renderer contains a number of *integrators* (selectable via the
renderer's API) which will combine the color closures computed by
surfaces and volumes with the light sources and view-dependent
information, to yield the amount of light visible to the camera.
```{image} Figures/integratorschematic.png
:width: 6.0in
```
<!--
At present, this document is written as if the integrators are built
into the renderer itself (or implemented as renderer plug-ins). At a
later time, we intend to make it possible for integrators themselves
to be written in OSL.
-->
#### Units
You can tell the renderer (through a global option) what units the scene
is using for distance and time. Then the shader has a built-in function
called `transformu()` that works a lot like `transform()`, but
instead of converting between coordinate systems, it converts among
units. For example,
```
displacement bumpy (float bumpdist = 1,
string bumpunits = "cm")
{
// convert bumpdist to common units
float spacing = transformu (bumpunits, "common", bumpdist);
float n = noise (P / spacing);
displace (n);
}
```
So you can write a shader to achieve some effect in real world units,
and that shader is totally reusable on another show that used different
modeling units.
It knows all the standard names like `cm`, `in`, `km`,
etc., and can convert among any of those, as well as between named
coordinate systems. For example,
```
float x = transformu ("object", "mm", 1);
```
now `x` is the number of millimeters per unit of "object" space on
that primitive.
[^rendererapi]: This document does not dictate a specific renderer API for
declaring shader instances, groups, and connections; the code above is just
an example of how it might be done.
+139
View File
@@ -0,0 +1,139 @@
#!/usr/bin/env python3
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# http://www.sphinx-doc.org/en/master/config
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
from __future__ import absolute_import
import sys
import os
import shlex
import subprocess
# -- Project information -----------------------------------------------------
# The master toctree document.
master_doc = 'index'
default_role = 'code'
project = 'Open Shading Language'
copyright = 'Contributors to the Open Shading Language project'
author = 'Larry Gritz, editor'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
# LG addition: we search for it in the CMakeLists.txt so we don't need to
# keep modifying this file:
version = '0.0'
release = '0.0.0'
import re
version_regex = re.compile(r'set \(OSL_VERSION \"?((\d+\.\d+)\.\d+)\.\d+\"?\)')
f = open('../../CMakeLists.txt')
for l in f:
aa=re.search(version_regex, l)
if aa is not None:
release = aa.group(1)
version = aa.group(2)
break
f.close()
print ("OSL docs version = {}, release = {}".format(version, release))
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
# add custom extensions directory to python path
sys.path.insert(0, os.path.join(os.path.abspath(os.path.dirname(__file__)), 'extensions/sphinxtr'))
sys.path.insert(0, os.path.join(os.path.abspath(os.path.dirname(__file__)), '../../ext/breathe'))
#import html_mods
#import latex_mods
extensions = [
'breathe',
'myst_parser',
'sphinx_tabs.tabs',
]
myst_enable_extensions = [
# "amsmath",
"attrs_inline",
"colon_fence",
"deflist",
"dollarmath",
"fieldlist",
# "html_admonition",
# "html_image",
# "linkify",
# "replacements",
# "smartquotes",
# "strikethrough",
# "substitution",
# "tasklist",
]
myst_heading_anchors = 3
# Add any paths that contain templates here, relative to this directory.
templates_path = ['templates']
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = []
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
#html_theme = 'alabaster'
#html_theme = 'astropy-sphinx-theme'
# html_theme = 'sphinx_rtd_theme'
html_theme = 'furo'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Breathe options
breathe_projects = { "osl": "../../build/doxygen/xml" }
breathe_default_project = "osl"
breathe_domain_by_extension = {'h': 'cpp'}
breathe_default_members = ()
primary_domain = 'cpp'
highlight_language = 'cpp'
read_the_docs_build = os.getenv('READTHEDOCS') == 'True'
if read_the_docs_build:
print ("cwd =", os.getcwd())
print ("checkpoint -- rtd build")
if not os.path.exists('../../build/doxygen') :
os.makedirs ('../../build/doxygen')
print ("checkpoint 2 -- rtd build")
subprocess.call('echo "Calling Doxygen"', shell=True)
subprocess.call(['doxygen'], shell=True)
subprocess.call('echo "Ran Doxygen"', shell=True)
+31
View File
@@ -0,0 +1,31 @@
<!--
Copyright Contributors to the Open Shading Language project.
SPDX-License-Identifier: CC-BY-4.0
-->
# Copyright Notice
The code that implements Open Shading Language is licensed under the BSD
3-clause (also sometimes known as "new BSD" or "modified BSD") license.
```{include} ../../LICENSE.md
```
This manual and other text documentation about OSL are licensed under the
Creative Commons Attribution 4.0 International License.
```{image} figures/CC-BY.png
:alt: Beautiful Sunset
:width: 200px
:align: center
```
http://creativecommons.org/licenses/by/4.0/
OSL incorporates code from several other software packages with
compatible licenses. Copies of their licenses are reproduced here:
https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/blob/master/THIRD-PARTY.md
+709
View File
@@ -0,0 +1,709 @@
---
numbering:
heading_1: true
heading_2: true
heading_3: true
---
<!--
Copyright Contributors to the Open Shading Language project.
SPDX-License-Identifier: CC-BY-4.0
-->
(chap-types)=
# Data types
OSL provides several built-in simple data types for performing
computations inside your shader:
Type | Explanation
:---------- | :-----------
`int` | Integer data
`float` | Scalar floating-point data (numbers)
`point`, `vector`, `normal` | Three-dimensional positions, directions, and face orientations
`color` | Spectral reflectivities and light energy values
`matrix` | $4 \times 4$ transformation matrices
`string` | Character strings (such as filenames)
`void` | Indicates functions that do not return a value
In addition, you may create arrays and structures (much like C), and
OSL has a new type of data structure called a *closure*.
The remainder of this chapter will describe the simple and aggregate
data types available in OSL.
(sec-datatypes-int)=
## `int`
The basic type for discrete numeric values is `int`. The size of
the `int` type is renderer-dependent, but is guaranteed to be at
least 32 bits.
Integer constants are constructed the same way as in C. The following
are examples of `int` constants: `1`, `-2`, etc. Integer
constants may be specified as hexadecimal, for example: `0x01cf`.
Unlike C, no unsigned, bool, char, short, or long types are supplied.
This is to simplify the process of writing shaders (as well as
implementing shading systems).
The following operators may be used with `int` values (in order of
decreasing precedence, with each box holding operators of the same
precedence):
Operation | Result | Explanation
:--------- | :------ | :---
*int* `++` | `int` | post-increment by 1
*int* `--` | `int` | post-decrement by 1
| |
| |
`++` *int* | `int` | pre-increment by 1
`--` *int* | `int` | pre-decrement by 1
`-` *int* | `int` | unary negation
`~` *int* | `int` | bitwise complement (1 and 0 bits flipped)
`!` *int* | `int` | boolean `not' (1 if operand is zero, otherwise 0)
| |
| |
*int* `*` *int* | `int` | multiplication
*int* `/` *int* | `int` | division
*int* `%` *int* | `int` | modulus
| |
| |
*int* `+` *int* | `int` | addition
*int* `-` *int* | `int` | subtraction
| |
| |
*int* `<<` *int* | `int` | shift left
*int* `>>` *int* | `int` | shift right
| |
| |
*int* `<` *int* | `int` | 1 if the first value is less than the second, else 0
*int* `<=` *int* | `int` | 1 if the first value is less or equal to the second, else 0
*int* `>` *int* | `int` | 1 if the first value is greater than the second, else 0
*int* `>=` *int* | `int` | 1 if the first value is greater than or equal to the second, else 0
| |
| |
*int* `==` *int* | `int` | 1 if the two values are equal, else 0
*int* `!=` *int* | `int` | 1 if the two values are different, else 0
| |
| |
*int* `&` *int* | `int` | bitwise and
| |
| |
*int* `^` *int* | `int` | bitwise exclusive or
| |
| |
*int* `\|` *int* | `int` | bitwise or
| |
| |
*int* `&&` *int* | `int` | boolean and (1 if both operands are nonzero, otherwise 0)
| |
| |
*int* `\|\|` *int* | `int` | boolean or (1 if either operand is nonzero, otherwise 0)
Note that the `not`, `and`, and `or` keywords are synonyms for `!`, `&&`, and
`||`, respectively.
## `float`
The basic type for scalar floating-point numeric values is `float`. The
size of the `float` type is renderer-dependent, but is guaranteed to
be at least IEEE 32-bit float (the standard C `float` data type).
Individual renderer implementations may choose to implement `float` with
even more precision (such as using the C `double` as the underlying
representation).
Floating-point constants are constructed the same way as in C. The following
are examples of `float` constants: `1.0`, `2.48`, `-4.3e2`.
An `int` may be used in place of a `float` when used with any valid
`float` operator. In such cases, the `int` will be promoted to a
`float` and the resulting expression will be `float`. An `int` may
also be passed to a function that expects a `float` parameters, with the
`int` automatically promoted to `float`.
The following operators may be used with `float` values (in order of
decreasing precedence, with each box holding operators of the same
precedence):
Operation | Result | Explanation
:--------- | :------ | :---
*float* `++` | `float` | post-increment by 1
*float* `--` | `float` | post-decrement by 1
| |
| |
`++` *float* | `float` | pre-increment by 1
`--` *float* | `float` | pre-decrement by 1
`-` *float* | `float` | unary negation
| |
| |
*float* `*` *float* | `float` | multiplication
*float* `/` *float* | `float` | division
| |
| |
*float* `+` *float* | `float` | addition
*float* `-` *float* | `float` | subtraction
| |
| |
*float* `<` *float* | `int` | 1 if the first value is less than the second, else 0
*float* `<=` *float* | `int` | 1 if the first value is less or equal to the second, else 0
*float* `>` *float* | `int` | 1 if the first value is greater than the second, else 0
*float* `>=` *float* | `int` | 1 if the first value is greater than or equal to the second, else 0
| |
| |
*float* `==` *float* | `int` | 1 if the two values are equal, else 0
*float* `!=` *float* | `int` | 1 if the two values are different, else 0
## `color`
The `color` type is used to represent 3-component (RGB) spectral
reflectivities and light energies. You can assemble a
color out of three floats, either representing an RGB triple or some
other color space known to the renderer, as well as from a single
float (replicated for all three channels). Following are some examples:
```
color (0, 0, 0) // black
color ("rgb", .75, .5, .5) // pinkish
color ("hsv", .2, .5, .63) // specify in "hsv" space
color (0.5) // same as color (0.5, 0.5, 0.5)
```
All these expressions above return colors in "rgb" space. Even the third
example returns a color in "rgb" space --- specifically, the RGB value of the
color that is equivalent to hue 0.2, saturation 0.5, and value 0.63. In other
words, when assembling a color from components given relative to a specific
color space in this manner, there is an implied transformation to "rgb" space.
The following table lists the built-in color spaces.
% \caption{Names of color spaces.}\label{tab:colorspacenames}
| | |
:--------- | :------
`"rgb"` | The coordinate system that all colors start out in, and in which the renderer expects to find colors that are set by your shader.
`"hsv"` | hue, saturation, and value.
`"hsl"` | hue, saturation, and lightness.
`"YIQ"` | the color space used for the NTSC television standard.
`"XYZ"` | CIE *XYZ* coordinates.
`"xyY"` | CIE *xyY* coordinates.
Colors may be assigned another color or a `float` value (which sets
all three components to the value). For example:
```
color C;
C = color (0, 0.3, 0.3);
C = 0.5; // same as C = color (0.5, 0.5, 0.5)
```
Colors can have their individual components examined and set using the
`[]` array access notation. For example:
```
color C;
float g = C[1]; // get the green component
C[0] = 0.5; // set the red component
```
Components 0, 1, and 2 are red, green, and blue, respectively.
It is an error to access a color component with an index outside the
$[0...2]$ range.
Color variables may also have their components referenced using "named
components" that look like accessing structure fields named `r`, `g`, and `b`,
as synonyms for `[0]`, `[1]`, and `[2]`, respectively:
```
float green = C.g; // get the green component
C.r = 0.5; // set the red component
```
The following operators may be used with `color` values (in order of
decreasing precedence, with each box holding operators of the same
precedence):
Operation | Result | Explanation
:--------- | :------ | :---
*color* `[` *int* `]` | `float` | component access
| |
| |
`-` *color* | `color` | unary negation
| |
| |
*color* `*` *color* | `color` | component-wise multiplication
*color* `*` *float* | `color` | scaling
*float* `*` *color* | `color` | scaling
*color* `/` *color* | `color` | component-wise division
*color* `/` *float* | `color` | scaling
*float* `/` *color* | `color` | scaling
| |
| |
*color* `+` *color* | `color` | component-wise addition
*color* `-` *color* | `color` | component-wise subtraction
| |
| |
*color* `==` *color* | `int` | 1 if the two values are equal, else 0
*color* `!=` *color* | `int` | 1 if the two values are different, else 0
All of the binary operators may combine a scalar value (`float` or
`int`) with a `color`, treating the scalar if it were a `color` with
three identical components.
## Point-like types: `point`, `vector`, `normal`
Points, vectors, and normals are similar data types with identical
structures but subtly different semantics. We will frequently refer to
them collectively as the "point-like" data types when making
statements that apply to all three types.
A `point` is a position in 3D space. A `vector` has a length and
direction, but does not exist in a particular location. A `normal` is a
special type of vector that is *perpendicular* to a surface, and
thus describes the surface's orientation. Such a perpendicular vector
uses different transformation rules than ordinary vectors, as we will
describe below.
All of these point-like types are internally represented by three
floating-point numbers that uniquely describe a position or
direction relative to the three axes of some coordinate system.
All points, vectors, and normals are described relative to some
coordinate system. All data provided to a shader (surface information,
graphics state, parameters, and vertex data) are relative to one
particular coordinate system that we call the `"common"` coordinate
system. The `"common"` coordinate system is one that is convenient
for the renderer's shading calculations.
You can "assemble" a point-like type out of three floats using a
constructor:
```
point (0, 2.3, 1)
vector (a, b, c)
normal (0, 0, 1)
```
These expressions are interpreted as a point, vector, and normal
whose three components are the floats given, relative to "common" space .
As with colors, you may also specify the coordinates relative to some other
coordinate system:
```
Q = point ("object", 0, 0, 0);
```
This example assigns to `Q` the point at the origin of "object" space.
However, this statement does *not* set the components of `Q` to (0,0,0)!
Rather, `Q` will contain the "common" space coordinates of the point that is
at the same location as the origin of "object" space. In other words, the
point constructor that specifies a space name implicitly specifies a
transformation to "common" space. This type of constructor also can be used
for vectors and normals.
The choice of "common" space is renderer-dependent, though will usually
be equivalent to either "camera" space or "world" space.
Some computations may be easier in a coordinate system other than
"common" space. For example, it is much more convenient to apply a
"solid texture" to a moving object in its "object" space than in
"common" space. For these reasons, OSL provides a built-in
`transform()` function that
allows you to transform points, vectors, and normals
among different coordinate systems (see Section [](#sec-stdlib-geom)). Note,
however, that OSL does not keep track of which point variables are
in which coordinate systems. It is the responsibility of the shader
programmer to keep track of this and ensure that, for example, lighting
computations are performed using quantities in "common" space.
Several coordinate systems are predefined by name, listed in the following
table. Additionally, a renderer will probably allow for additional coordinate
systems to be named in the scene description, and these names may also be
referenced inside your shader to designate transformations.
% \caption{Names of predeclared geometric spaces.\label{tab:spacenames}}
`"common"`
: The coordinate system that all spatial values start out in and the one in
which all lighting calculations are carried out. Note that the choice of
`"common"` space may be different on each renderer.
`"object"`
: The local coordinate system of the graphics primitive (sphere, patch, etc.)
that we are shading.
`"shader"`
: The local coordinate system active at the time that the shader was
instanced.
`"world"`
: The world coordinate system designated in the scene.
`"camera"`
: The coordinate system with its origin at the center of the camera lens,
$x$-axis pointing right, $y$-axis pointing up, and $z$-axis pointing into
the screen.
`"screen"`
: The coordinate system of the camera's image plane (after perspective
transformation, if any). Coordinate (0,0) of `"screen"` space is looking
along the $z$-axis of "camera" space.
`"raster"`
: 2D pixel coordinates, with (0,0) as the upper-left
corner of the image and (xres, yres) as the lower-right corner.
`"NDC"`
: 2D Normalized Device Coordinates --- like raster space, but normalized so
that $x$ and $y$ both run from 0 to 1 across the whole image, with (0,0)
being at the upper left of the image, and (1,1) being at the lower right.
Point types can have their individual components examined and set using
the `[]` array access notation. For example:
```
point P;
float y = P[1]; // get the y component
P[0] = 0.5; // set the x component
```
Components 0, 1, and 2 are $x$, $y$, and $z$, respectively.
It is an error to access a point component with an index outside the
$[0...2]$ range.
Point-like variables may also have their components referenced using "named
components" that look like accessing structure fields named `x`, `y`, and `z`,
as synonyms for `[0]`, `[1]`, and `[2]`, respectively:
```
float yval = P.y; // get the [1] or y component
P.x = 0.5; // set the [0] or x component
```
The following operators may be used with point-like values (in order of
decreasing precedence, with each box holding operators of the same
precedence):
Operation | Result | Explanation
:--------- | :------ | :---
*ptype* `[` `int` `]` | `float` | component access
| |
| |
`-` *ptype* | `vector` | component-wise unary negation
| |
| |
*ptype* `*` *ptype* | *ptype* | component-wise multiplication
`float` `*` *ptype* | *ptype* | scaling of all components
*ptype* `*` `float` | *ptype* | scaling of all components
*ptype* `/` *ptype* | *ptype* | component-wise division
*ptype* `/` `float` | *ptype* | division of all components
`float` `/` *ptype* | *ptype* | division by all components
| |
| |
*ptype* `+` *ptype* | *ptype* | component-wise addition
*ptype* `-` *ptype* | `vector` | component-wise subtraction
| |
| |
*ptype* `==` *ptype* | `int` | 1 if the two values are equal, else 0
*ptype* `!=` *ptype* | `int` | 1 if the two values are different, else 0
The generic *ptype* is listed in places where any of `point`, `vector`, or
`normal` may be used.
All of the binary operators may combine a scalar value (`float` or `int`) with
a point-like type, treating the scalar if it were point-like with three
identical components.
## `matrix`
OSL has a `matrix` type that represents the transformation matrix required to
transform points and vectors between one coordinate system and another.
Matrices are represented internally by 16 floats (a $4 \times 4$ homogeneous
transformation matrix).
A `matrix` can be constructed from a single float or 16 floats. For example:
```
matrix zero = 0; // makes a matrix with all 0 components
matrix ident = 1; // makes the identity matrix
// Construct a matrix from 16 floats
matrix m = matrix (m00, m01, m02, m03, m10, m11, m12, m13,
m20, m21, m22, m23, m30, m31, m32, m33);
```
Assigning a single floating-point number $x$ to a matrix will result
in a matrix with diagonal components all being $x$ and other
components being zero (i.e., $x$ times the identity matrix).
Constructing a matrix with 16 floats will create the matrix whose
components are those floats, in row-major order.
Similar to point-like types, a `matrix` may be constructed in
reference to a named space:
```
// Construct matrices relative to something other than "common"
matrix q = matrix ("shader", 1);
matrix m = matrix ("world", m00, m01, m02, m03, m10, m11, m12, m13,
m20, m21, m22, m23, m30, m31, m32, m33);
```
The first form creates the matrix that transforms points from "shader" space
to "common" space. Transforming points by this matrix is identical to calling
`transform("shader", "common", ...)`. The second form prepends the
current-to-world transformation matrix onto the $4 \times 4$ matrix with
components $m_{0,0} ... m_{3,3}$. Note that although we have used `"shader"`
and `"world"` space in our examples, any named space is acceptable.
A matrix may also be constructed from the names of two coordinate
systems, yielding the matrix that transforms coordinates from the
first named space to the second named space:
```
matrix m = matrix ("object", "world");
```
The example returns the *object-to-world* transformation matrix.
Matrix variables can be tested for equality and inequality with the `==` and
`!=` boolean operators. Also, the `*` operator between matrices denotes
matrix multiplication, while `m1 / m2` denotes multiplying `m1` by the inverse
of matrix `m2`. Thus, a matrix can be inverted by writing `1/m`. In
addition, some functions will accept matrix variables as arguments, as
described in Section [](#chap-stdlibrary).
Individual components of a matrix variable may be set or accessed using array
notation, for example,
```
matrix M;
float x = M[row][col];
M[row][col] = 1;
```
Valid component indices are integers on $[0...3]$. It is an error to access a
matrix component with either a row or column outside this range.
The following operators may be used with matrices (in order of decreasing
precedence, with each box holding operators of the same precedence):
Operation | Result | Explanation
:--------- | :------ | :---
*matrix* `[` *int* `][` *int* `]` | `float` | component access (row, column)
| |
| |
`-` *matrix* | `matrix` | unary negation
| |
| |
*matrix* `*` *matrix* | `matrix` | matrix multiplication
*matrix* `*` *float* | `matrix` | component-wise scaling
*float* `*` *matrix* | `matrix` | component-wise scaling
*matrix* `/` *matrix* | `matrix` | multiply the first matrix by the *inverse of the second
*matrix* `/` *float* | `matrix` | component-wise division
*float* `/` *matrix* | `matrix` | multiply the *float* by the *inverse of the matrix
| |
| |
*matrix* `==` *matrix* | *int* | 1 if the two values are equal, else 0
*matrix* `!=` *matrix* | *int* | 1 if the two values are different, else 0
## `string`
The `string` type may hold character strings. The main application
of strings is to provide the names of files where textures may be
found. Strings can be compared using `==` and `!=`.
String constants are denoted by surrounding the characters with double
quotes, as in `"I am a string literal"`. As in C programs, string
literals may contain escape sequences such as `\n` (newline),
`\r` (carriage return), `\t` (tab), `\"` (double quote),
`\\` (backslash).
Two quote-quoted string literals that are separated only by whitespace
(spaces, tabs, or newlines) will be automatically concatenated into a
single string literal. In other words,
```text
"foo" "bar"
```
is exactly equivalent to `"foobar"`.
## `void`
The `void` type is used to designate a function that does not return a value.
No variable may have type `void`.
## Arrays
Arrays of any of the basic types are supported, provided that they
are 1D and statically sized, using the usual syntax for C-like languages:
```
float d[10]; // Declare an uninitialized array
float c[3] = { 0.1, 0.2, 3.14 }; // Initialize the array
float f = c[1]; // Access one element
```
The built-in function `arraylength()` returns the number of elements in an
array. For example:
```
float c[3];
int clen = arraylength(c); // should return 3
```
There are two circumstances when arrays do not need to have a declared
length --- an array parameter to a function, and a shader parameter that
is an array. This is indicated by empty array brackets, as shown in the
following example:
```
float sum (float x[])
{
float s = 0;
for (int i = 0; i < arraylength(x); ++i)
s += x[i];
return s;
}
```
It is allowed in OSL to copy an entire array at once using the `=` operator,
provided that the arrays contain elements of the same type and that the
destination array is at least as long as the source array. For example:
```
float array[4], anotherarray[4];
...
anotherarray = array;
```
## Structures
Structures are used to group several fields of potentially different types
into a single object that can be referred to by name. You may then use the
structure type name to declare structure variables as you would for any of the
built-in types. Structure elements are accessed using the `.` ("dot")
operator. The syntax for declaring and using structures is similar to C or
C++:
```
struct RGBA { // Define a structure type
color rgb;
float alpha;
};
RGBA col; // Declare a structure
r.rgb = color (1, 0, 0); // Assign to one field
color c = r.rgb; // Read from a structure field
RGBA b = { color(.1,.2,.3), 1 }; // Member-by-member initialization
```
You can use "constructor expressions" for a your struct types much like
you can construct built-in types like `color` or `point`:
> *struct_name* `(` *first_member_value*, ... `}`
For example,
```
RGBA c = RGBA(col,alpha); // Constructor syntax
RGBA add (RGBA a, RGBA b)
{
return RGBA (a.rgb+b.rgb, a.a+b.a); // return expression
}
// pass constructor expression as a parameter:
RGBA d = add (c, RGBA(color(.3,.4,.5), 0));
```
You may also use the *compound initializer list* syntax to construct a type
when it can be deduced from context which compound type is required. For
example, this is equivalent to the preceding example:
```
RGBA c = {col,alpha}; // deduce by what is being assigned to
RGBA add (RGBA a, RGBA b)
{
return { a.rgb+b.rgb, a.a+b.a }; // deduce by func return type
}
RGBA d = add (c, {{.3,.4,.5}, 0}); // deduce by expected arg type
```
It is permitted to have a structure field that is an array, as well as to have
an array of structures. But it is not currently permitted to "nest" arrays
(that is, to have an array of structs which contain members that are arrays).
```
struct A {
color a;
float b[4]; // Ok: struct may contain an array
};
RGBA vals[4]; // Ok: Array of structures
vals[0].a = 0;
A d[5]; // NO: Array of structures that contain arrays
```
## Closures
A `closure`is an expression or function call that will be stored, along
with necessary contextual information, to be evaluated at a later time.
In general, the type "`closure` *gentype*" behaves exactly like a
*gentype*, except that its numeric values may not be examined or
used for the duration of the shader's execution. For example, a
`color closure` behaves mostly like a color --- you can multiply it by a
scalar, assign it to a `color closure` variable, etc. --- but you may not
assign it to an ordinary `color` or examine its individual component's
numeric values.
It is legal to assign `0` to a closure, which is understood to mean setting it
to a *null closure* (even though in all other circumstances, assigning a
`float` to a `closure`would not be allowed).
At present, the only type of `closure`supported by OSL is the `color closure`,
and the only allowed operations are those that let you form a linear
combination of `color closure`'s. Additional closure types and operations are
reserved for future use.
Allowable operations on `color closure` include:
Operation | Result | Explanation
:--------- | :------ | :---
`-` *colorclosure* | `color closure` | unary negation
| |
| |
*color* `*` *colorclosure* | `color closure` | component-wise scaling
*colorclosure* `*` *color* | `color closure` | component-wise scaling
*float* `*` *colorclosure* | `color closure` | scaling
*colorclosure* `*` *float* | `color closure` | scaling
| |
| |
*colorclosure* `+` *colorclosure* | `color closure` | component-wise addition
% *colorclosure* `-` *colorclosure* | `color closure` | component-wise subtraction
+174
View File
@@ -0,0 +1,174 @@
<!--
Copyright Contributors to the Open Shading Language project.
SPDX-License-Identifier: CC-BY-4.0
-->
(chap-glossary)=
# Glossary
Attribute state
: The set of variables that determines all the properties (other than shape)
of a *geometric primitive* --- such as its local transformation matrix,
the surface, displacement, and volume shaders to be used, which light
sources illuminate objects that share the attribute state, whether
surfaces are one-sided or two-sided, etc. Basically all of the options
that determine the behavior and appearance of the primitives, that are not
determined by the shape itself or the code of the shaders. A single
attribute state may be shared among multiple geometric primitives. Also
sometimes called *graphics state*.
BSDF
: Bidirectional scattering distribution function, a function that describes
light scattering properties of a surface.
Built-in function
: A function callable from within a shader, where the implementation of the
function is provided by the renderer (as opposed to a function that the
shader author writes in OSL itself).
Closure
: A symbolic representation of a function to be called, and values for its
parameters, that are packaged up to be evaluated at a later time to yield
a final numeric value.
Connection
: A routing of the value of an *output parameter* of one *shader layer* to
an *input parameter* of another shader layer within the same *shader
group*.
Default parameter value
: The initial value of a *shader parameter*, if the renderer does not
override it with an *instance value*, an interpolated *primitive
variable*, or a *connection* to an output parameter of another *layer*
within the *group*. The default value of a shader parameter is explicitly
given in the code for that shader, and may either be a constant or a
computed expression.
EDF
: Emission distribution function, a function that describes the distribution
of light emitted by a light source.
Geometric primitive
: A single shape, such as a NURBS patch, a polygon or subdivision mesh, a
hair primitive, etc.
Global variables
: The set of "built-in" variables describing the common renderer inputs to
all shaders (as opposed to shader-specific parameters). These include
position (`P`), surface normal (`N`), surface tangents (`dPdu`, `dPdv`),
as well as standard radiance output (`Ci`). Different *shader types*
support different subsets of the global variables.
Graphics state
: See *attribute state*.
Group
: See *shader group*.
Input parameter
: A read-only *shader parameter* that provides a value to control a
shader's behavior. Can also refer to a read-only parameter to a
*shader function*.
Instance value
: A constant value that overrides a default parameter value for a
particular *shader instance*. Each instance of a shader may have a
completely different set of instance values for its parameters.
Layer
: See *shader layer*.
Output parameter
: A read/write *shader parameter* allows a shader to provide outputs beyond
the *global variables* such as `Ci`. Can also refer to a read/write
parameter to a *shader function*, allowing a function to provide more
outputs than a simple return value.
Primitive
: Usually refers to a *geometric primitive*.
Primitive variable
: A named variable, and values, attached to an individual geometric
primitive. Primitive variables may have one of several *interpolation
methods* --- such as a single value for the whole primitive, a value for
each piece or face of the primitive, or per-vertex values that are
smoothly interpolated across the surface.
% Public method
%
% : A function within a shader that has an entry point that is visible and
% directly callable by the renderer, as opposed to merely being called from
% other code within the shader. Public methods must be *top-level* (not
% defined within other functions) and must be preceded by the `public`
% keyword.
Shader
: A small self-contained program written in OSL, used to extend the
functionality of a renderer with custom behavior of materials and lights.
A particular shader may have multiple *shader instances* within a scene,
each of which has its unique *instance parameters*, transformation, etc.
Shader function
: A function written in OSL that may be called from within a shader.
Shader group
: An ordered collection of *shader instances* (individually called the
*layers* of a group) that are executed to collectively determine material
properties or displacement of a geometric primitive, emission of a light
source, or scattering properties of a volume. In addition to executing
sequentially, layers within a group may optionally have any of their input
parameters explicitly connected to output parameters of other layers
within the group in an acyclic manner (thus, sometimes being referred to
as a *shader network*).
Shader instance
: A particular reference to a *shader*, with a unique set of *instance
values*, transformation, and potentially other attributes. Each shader
instance is a separate entity, despite their sharing executable code.
Shader network
: See *shader group*.
Shader layer
: An individual *shader instance* within a *shader group*.
Shader parameter
: A named input or output variable of a shader. *Input parameters* provide
"knobs" that control the behavior of a shader; *output parameters*
additional provide a way for shaders to produce additional output beyond
the usual *global variables*.
Shading
: The computations within a renderer that implement the behavior and visual
appearance of materials and lights.
VDF
: Volumetric distribution function, a function that describes the scattering
properties of a volume.
+239
View File
@@ -0,0 +1,239 @@
---
numbering:
heading_1: true
heading_2: true
heading_3: true
---
<!--
Copyright Contributors to the Open Shading Language project.
SPDX-License-Identifier: CC-BY-4.0
-->
(chap-grammar)=
# Formal Language Grammar
This section gives the complete syntax of OSL. Syntactic structures that have
a name ending in `-opt` are optional. Structures surrounded by curly braces
`{ }` may be repeated 0 or more times. Text in `typewriter` face indicates
literal text. The $\epsilon$ character is used to indicate that it is
acceptable for there to be nothing (empty, no token).
#### Lexical elements
\<digit\> ::= "`0`" | "`1`" | "`2`" | "`3`" | "`4`" | "`5`" | "`6`" | "`7`" | "`8`" | "`9`"
\<digit-sequence\> ::= \<digit\> { \<digit\> }
\<hexdigit\> ::= \<digit\> | "`a`" | "`A`" | "`b`" | "`B`" | "`c`" | "`C`" | "`d`" | "`D`" | "`e`" | "`E`" | "`f`" | "`F`"
\<hexdigit-sequence\> ::= \<hexdigit\> { \<hexdigit\> }
\<integer\> ::= \<sign\> \<digit-sequence\>
<br>$~~~~~~~~~~$ | \<sign\> "`0x`" \<hexdigit-sequence\>
\<floating-point\> ::= \<digit-sequence\> \<decimal-part-opt\> \<exponent-opt\>
<br>$~~~~~~~~~~$ | \<decimal-part\> \<exponent-opt\>
\<decimal-part\> ::= '`.`' { \<digit\> }
\<exponent\> ::= '`e`' \<sign\> \<digit-sequence\>
\<sign\> ::= '`-`' | '`+`' | $\epsilon$
\<number\> ::= \<integer\>
<br>$~~~~~~~~~~$ | \<floating-point\>
\<char-sequence\> ::= { \<any-char\> }
\<stringliteral> ::= `"` \<char-sequence\> `"`
\<identifier\> ::= \<letter-or-underscore\> { \<letter-or-underscore-or-digit\> }
#### Overall structure
\<shader-file\> ::= { \<global-declaration\> }
\<global-declaration\> ::= \<function-declaration\>
<br>$~~~~~~~~~~$ | \<struct-declaration\>
<br>$~~~~~~~~~~$ | \<shader-declaration\>
\<shader-declaration\> ::= <br>$~~~~~~~~~~~~$ $~~~~~~~~~~$
\<shadertype\> \<identifier\> \<metadata-block-opt\>
"(" \<shader-formal-params-opt\> ")" "{" \<statement-list\> "}"
\<shadertype\> ::= "displacement" | "shader" | "surface" | "volume"
\<shader-formal-params\> ::= \<shader-formal-param\> { "," \<shader-formal-param\> }
\<shader-formal-param\> ::= \<outputspec\> \<typespec\> \<identifier\>
\<initializer\> \<metadata-block-opt\>
<br>$~~~~~~~~~~$ | \<outputspec\> \<typespec\> \<identifier\> \<arrayspec\>
\<initializer-list\> \<metadata-block-opt\>
\<metadata-block> ::= "[[" \<metadata\> { "," \<metadata\> } "]]"
\<metadata\> ::= \<simple-typespec\> \<identifier\> \<initializer\>
#### Declarations
\<function-declaration\> ::= <br>$~~~~~~~~~~~~$ \<typespec\> \<identifier\>
"(" \<function-formal-params-opt\> ")" "{" \<statement-list\> "}"
\<function-formal-params\> ::= \<function-formal-param\> { "," \<function-formal-param\> }
\<function-formal-param\> ::= \<outputspec\> \<typespec\> \<identifier\> \<arrayspec-opt\>
\<outputspec> ::= "output" | $\epsilon$
\<struct-declaration\> ::= "struct" \<identifier\> "{" \<field-declarations> "}" ";"
\<field-declarations\> ::= \<field-declaration\> { \<field-declaration\> }
\<field-declaration\> ::= \<typespec\> \<typed-field-list\> ";"
\<typed-field-list\> ::= \<typed-field\> { "," \<typed-field\> }
\<typed-field\> ::= \<identifier\> \<arrayspec-opt\>
\<local-declaration\> ::= \<function-declaration\>
<br>$~~~~~~~~~~$ | \<variable-declaration\>
\<arrayspec> ::= "[" \<integer\> "]"
<br>$~~~~~~~~~~$ | "[" "]"
\<variable-declaration\> ::= \<typespec\> \<def-expressions> ";"
\<def-expressions\> ::= \<def-expression\> { "," <def-expression\> }
\<def-expression\> ::= \<identifier\> \<initializer-opt\>
<br>$~~~~~~~~~~$ | \<identifier\> \<arrayspec\> \<initializer-list-opt\>
\<initializer\> ::= "=" \<expression\>
\<initializer-list\> ::= "=" \<compound-initializer\>
\<compound-initializer\> ::= "{" \<init-expression-list\> "}"
\<init-expression-list\> ::= \<init-expression\> { "," \<init-expression\> }
\<init-expression\> ::= \<expression\> | \<compound-initializer\>
\<typespec\> ::= \<simple-typename>
<br>$~~~~~~~~~~$ | "closure" \<simple-typename\>
<br>$~~~~~~~~~~$ | \<identifier-structname\>
\<simple-typename\> ::=
"color"
| "float"
| "matrix"
| "normal"
| "point"
| "string"
| "vector"
| "void"
#### Statements
\<statement-list\> ::= \<statement\> { \<statement\> }
\<statement\> ::=
\<compound-expression-opt\> ";"
<br>$~~~~~~~~~~$ | \<scoped-statements\>
<br>$~~~~~~~~~~$ | \<local-declaration\>
<br>$~~~~~~~~~~$ | \<conditional-statement\>
<br>$~~~~~~~~~~$ | \<loop-statement\>
<br>$~~~~~~~~~~$ | \<loopmod-statement\>
<br>$~~~~~~~~~~$ | \<return-statement\>
\<scoped-statements> ::= "{" \<statement-list-opt\> "}"
\<conditional-statement\> ::= <br>$~~~~~~~~~~~~$ "if" "(" \<compound-expression\> ")" \<statement\>
<br>$~~~~~~~~~~$ | "if" "(" \<compound-expression\> ")" \<statement\> "else" \<statement\>
\<loop-statement\> ::= <br>$~~~~~~~~~~~~$ "while" "(" \<compound-expression\> ")" \<statement\>
<br>$~~~~~~~~~~$ | "do" \<statement\> "while" "(" \<compound-expression\> ")" ";"
<br>$~~~~~~~~~~$ | "for" "(" \<for-init-statement-opt\> \<compound-expression-opt\> ";"
\<compound-expression-opt\> ")" \<statement\>
\<for-init-statement\> ::= <br>$~~~~~~~~~~~~$ \<expression-opt\> ";"
<br>$~~~~~~~~~~$ | \<variable-declaration\>
\<loopmod-statement\> ::= "break" ";"
<br>$~~~~~~~~~~$ | "continue" ";"
\<return-statement\> ::= "return" \<expression-opt\> ";"
#### Expressions
\<expression-list\> ::= \<expression\> { "," \<expression\> }
\<expression\> ::= \<number\>
<br>$~~~~~~~~~~$ | \<stringliteral\>
<br>$~~~~~~~~~~$ | \<type-constructor\>
<br>$~~~~~~~~~~$ | \<incdec-op\> \<variable-ref\>
<br>$~~~~~~~~~~$ | \<expression\> \<binary-op\> \<expression\>
<br>$~~~~~~~~~~$ | \<unary-op\> \<expression\>
<br>$~~~~~~~~~~$ | "(" \<compound-expression\> ")"
<br>$~~~~~~~~~~$ | \<function-call\>
<br>$~~~~~~~~~~$ | \<assign-expression\>
<br>$~~~~~~~~~~$ | \<ternary-expression\>
<br>$~~~~~~~~~~$ | \<typecast-expression\>
<br>$~~~~~~~~~~$ | \<variable-ref\>
<br>$~~~~~~~~~~$ | \<compound-initializer\>
\<compound-expression\> ::= \<expression\> { "," \<expression\> }
\<variable-lvalue\> ::= \<identifier\> \<array-deref-opt\> \<component-deref-opt\>
<br>$~~~~~~~~~~$ | \<variable_lvalue> "[" \<expression\> "]"
<br>$~~~~~~~~~~$ | \<variable_lvalue> "." \<identifier\>
\<variable-ref\> ::= \<identifier\> \<array-deref-opt\>
\<array-deref> ::= "[" \<expression\> "]"
\<component-deref> ::= "[" \<expression\> "]"
<br>$~~~~~~~~~~$ | "." \<component-field\>
\<component-field\> ::= "x" | "y" | "z" | "r" | "g" | "b"
\<binary-op> ::= "*" | "/" | "\%"
<br>$~~~~~~~~~~$ | "+" | "-"
<br>$~~~~~~~~~~$ | "<<" | ">>"
<br>$~~~~~~~~~~$ | "<" | "<=" | ">" | ">="
<br>$~~~~~~~~~~$ | "==" | "!="
<br>$~~~~~~~~~~$ | "&"
<br>$~~~~~~~~~~$ | "^"
<br>$~~~~~~~~~~$ | "|"
<br>$~~~~~~~~~~$ | "&&" | "and"
<br>$~~~~~~~~~~$ | "||" | "or"
\<unary-op> ::= "-" | "~" | "!" | "not"
\<incdec-op> ::= "++" | "--"
\<type-constructor\> ::= \<typespec> "(" \<expression-list\> ")"
\<function-call\> ::= \<identifier\> "(" \<function-args-opt\> ")"
\<function-args\> ::= \<expression\> { "," \<expression\> }
\<assign-expression\> ::= \<variable-lvalue\> \<assign-op\> \<expression\>
\<assign-op> ::= "=" | "*=" | "/=" | "+=" | "-=" | "&=" | "|=" | "^=" |
"<<=" | ">>="
\<ternary-expression\> ::= \<expression\> "?" \<expression\> ":" \<expression\>
\<typecast-expression\> ::= "(" \<simple-typename> ")" \<expression\>
+403
View File
@@ -0,0 +1,403 @@
<!--
Copyright Contributors to the Open Shading Language project.
SPDX-License-Identifier: CC-BY-4.0
-->
# Gross syntax, shader types, parameters
The overall structure of a shader is as follows:
> *optional-function-or-struct-declarations* \
\
shader-type shader-name `(` optional-parameters `)` \
`{` \
*statements* \
`}`
Note that *statements* may include function or structure definitions, local
variable declarations, or public methods, as well as ordinary execution
instructions (such as assignments, etc.).
## Shader types
Shader types include the following: `surface`, `displacement`, `light`,
`volume`, and generic `shader`. Some operations may only be performed from
within certain types of shaders (e.g., one may only call `displace()` or alter
`P` in a displacement shader), and some global variables may only be accessed
from within certain types of shaders (e.g., `dPdu` is not defined inside a
volume shader).
Following are brief descriptions of the basic types of shaders:
`surface` shaders
: Surface shaders determine the basic material properties of a surface and
how it reacts to light. They are responsible for computing a
`color closure` that describes the material, and optionally setting
other user-defined output variables. They may not alter
the position of the surface.
Surface shaders are written as if they describe the behavior of a single
point on the primitive, and the renderer will choose the positions
surface at which the shader must be evaluated.
Surface shaders also are used to describe emissive objects, i.e., light
sources. OSL does not need a separate shader type to describe lights.
`displacement` shaders
: Displacement shaders alter the position and shading normal (or,
optionally, just the shading normal) to make a piece of geometry appear
deformed, wrinkled, or bumpy. They are the only kind of shader that
is allowed to alter a primitive's position.
`volume` shaders
: Volume shaders describe how a participating medium (air, smoke, glass,
etc.) reacts to light and affects the appearance of objects on the other
side of the medium. They are similar to `surface` shaders, except
that they may be called from positions that do not lie upon (and are not
necessarily associated with) any particular primitive.
`shader` generic shaders
: Generic shaders are used for utility code, generic routines that may be
called as individual layers in a shader group. Generic shaders need not
specify a shader type, and therefore may be reused from inside surface,
displacement, or volume shader groups. But as a result, they may
not contain any functionality that cannot be performed from inside all
shader types (for example, they may not alter `P`, which can only be done
from within a displacement shader).
## Shader parameters
An individual shader has (optionally) many *parameters* whose
values may be set in a number of ways so that a single shader may have
different behaviors or appearances when used on different objects.
### Shader parameter syntax
Shader parameters are specified in the shader declaration, in
parentheses after the shader's name. This is much like the parameters
to an OSL function (or a function in C or similar languages),
except that shader parameters must have an *initializer*, giving a
default value for the parameter. Shader parameter default initializers
may be expressions (i.e., may be computed rather than restricted to
numeric constants), and are evaluated in the order that the parameters
are declared, and may include references to previously-declared
parameters. Formally, the grammar for a simple parameter
declaration looks like this:
> *type parametername* `=` *default-expression*
where *type* is one of the data types described in Chapter [](#chap-types),
*parametername* is the name of the parameter, and *default-expression* is a
valid expression (see Section [](#sec-expressions)). Multiple parameters are
simply separated by commas:
> *type1 parameter1* `=` *expr1* `,` *type2 parameter2* `=` *expr2* `,` ...
Fixed-length, one-dimensional array parameters are declared as follows:
> *type parametername* `[` *array-length* `] = {` *expr0* `,` *expr1* ... `}`
where *array-length* is a positive integer constant giving the length of the
array, and the initializer is a series of initializing expressions listed
between curly braces. The first initializing expression provides the
initializer for the first element of the array, the second expression provides
the initializer for the second element of the array, and so on. If the number
of initializing expressions is less than the length of the array, any
additional array elements will have undefined values.
Arrays may also be declared without a set length:
> *type parametername* `[ ] = {` *expr0* `,` *expr1* ... `}`
where no array length is found between the square brackets.
This indicates that the array's length will be determined based on
whatever is passed in --- a connection from the output of another shader
in the group (take on the length of that output), an instance value
(take on the length specified by the declaration of the instance value),
or a primitive variable (length determined by its declaration on the
primitive). If no instance value, primitive value, or connection is
supplied, then the number of initializing expressions will determine the
length, as well as the default values, of the array.
Structure parameters are also straightforward to declare:
> *structure-type parametername* `= {` *expr0* `,` *expr1* ... `}`
where *structure-type* is the name of a previously-declared `struct` type, and
the *expr* initializers correspond to each respective field within the
structure. An initializer of appropriate type is required for every field of
the structure.
### Shader output parameters
Shader parameters are, by default, read-only in the body of the
shader. However, special \emph{output parameters} may be altered
by execution of the shader. Parameters may be designated outputs
by use of the {\cf output} keyword immediately prior to the
type declaration of the parameter:
> `output` *type parametername* `=` *expr*
(Output parameters may be arrays and structures, but we will omit spelling out
the obvious syntax here.)
Output parameters may be connected to inputs of later-run shader layers in the
shader group, may be queried by later-run shaders in the group via message
passing (i.e., `getmessage()` calls), or used by the renderer as an output
image channel (in a manner described through the renderer's API).
### Shader parameter example
Here is an example of a shader declaration, with several parameters:
```
surface wood (
/* Simple params with constant initializers */
float Kd = 0.5,
color woodcolor = color (.7, .5, .3),
string texturename = "wood.tx",
/* Computed from an earlier parameter */
color ringcolor = 0.25 * woodcolor,
/* Fixed-length array */
color paintcolors[3] = { color(0,.25,0.7), color(1,1,1),
color(0.75,0.5,0.2) },
/* variable-length array */
int pattern[] = { 2, 4, 2, 1 },
/* output parameter */
output color Cunlit = 0
)
{
...
}
```
### How shader parameters get their values
Shader parameters get their values in the following manner,
in order of decreasing priority:
1. If the parameter has been designated by the renderer to be connected to an
output parameter of a previously-executed shader layer within the shader
group, that is the value it will get.
2. If the parameter matches the name and type of a per-primitive, per-face, or
per-vertex *primitive variable* on the particular piece of geometry
being shaded, the parameter's value will be computed by interpolating the
primitive variable for each position that must be shaded.
3. If there is no connection or primitive variable, the parameter may will
take on an *instance value*, if that parameter was given an explicit
per-instance value at the time that the renderer referenced the shader
(associating it with an object or set of objects).
4. If none of these overrides is present, the parameter's value will be
determined by executing the parameter initialization code in the shader.
This triage is performed per parameter, in order of declaration. So, for
example, in the code sample above where the default value for `ringcolor1 is a
scaled version of `woodcolor`, this relationship would hold whether
`woodcolor` was the default, an instance value, an interpolated primitive
value, or was connected to another layer's output. Unless `ringcolor` itself
was given an instance, primitive, or connection value, in which case that's
what would be used.
## Shader metadata
A shader may optionally include *metadata* (data *about* the
shader, as opposed to data *used by* the shader). Metadata may be
used to annotate the shader or any of its individual parameters with
additional hints or information that will be compiled into the shader
and may be queried by applications. A common use of metadata is to
specify user interface hints about shader parameters --- for example,
that a particular parameter should only take on integer values, should
have an on/off checkbox, is intended to be a filename, etc.
Metadata is specified inside double brackets `[[` and `]]` enclosing a
comma-separated list of metadata items. Each metadatum looks like a parameter
declaration --- having a data type, name, and initializer. However, metadata
may only be simple types or arrays of simple types (not structs or closures)
and their value initializers must be numeric or string constants (not computed
expressions).
Metadata about the shader as a whole is placed between the shader name
and the parameter list. Metadata about shader parameters are placed
immediately after the parameter's initializing expression, but before
the comma or closing parentheses that terminates the parameter
description.
Below is an example shader declaration showing the use of shader and
parameter metadata:
```
surface wood
[[ string help = "Realistic wood shader" ]]
(
float Kd = 0.5
[[ string help = "Diffuse reflectivity",
float min = 0, float max = 1 ]] ,
color woodcolor = color (.7, .5, .3)
[[ string help = "Base color of the wood" ]],
color ringcolor = 0.25 * woodcolor
[[ string help = "Color of the dark rings" ]],
string texturename = "wood.tx"
[[ string help = "Texture map for the grain",
string widget = "filename" ]],
int pattern = 0
[[ string widget = "mapper",
string options = "oak:0|elm:1|walnut:2" ]]
)
{
...
}
```
The metadata are not semantically meaningful; that is, the metadata does
not affect the actual execution of the shader. Most metadata exist only
to be embedded in the compiled shader and able to be queried by other
applications, such as to construct user interfaces for shader assignment
that allow usage tips, appropriate kinds of widgets for setting each
parameter, etc.
The choice of metadata and their meaning is completely up to the shader
writer and/or modeling system. However, we propose some conventions
below. These conventions are not intended to be comprehensive, nor to
meet all your needs --- merely to establish a common nomenclature for
the most common metadata uses.
The use of metadata is entirely optional on the part of the shader
writer, and any application that queries shader metadata is free to
honor or ignore any metadata it finds.
string label
: A short label to be displayed in the UI for this parameter. If not
present, the parameter name itself should be used as the widget label.
string help
: Help text that describes the purpose and use of the shader or parameter.
string page
: Helps to group related widgets by ``page.''
string widget
: The type of widget that should be used to adjust this parameter.
Suggested widget types:
"number"
: Provide a slider and/or numeric input. This is the default widget type for
`float` or `int` parameters. Numeric inputs also may be influenced by the
following metadata: `min`, `max`, `sensitivity`, `digits`, `slider`,
`slidermin`, `slidermax`, `slidercenter`, `sliderexponent`.
"string"
: Provide a text entry widget. This is the default widget type for
{\cf string} parameters.
"boolean"
: Provide a pop-up menu with "Yes" and "No" options. Works on strings
or numbers. With strings, "Yes" and "No" values are used, with
numbers, 0 and 1 are used.
"checkBox"
: A boolean widget displayed as a checkbox. Works on strings or
numbers. With strings, "Yes" and "No" values are used, with numbers,
0 and 1 are used.
"popup"
: A pop-up menu of literal choices. This widget further requires
parameter metadata `options` (a string listing the supported
menu items, delimited by the `|` character), and optionally `editable`
(an integer, which if nonzero means the widget should allow the
text field should be directly editable). For example:
```
string wrap = "default"
[[ string widget = "popup",
string options = "default|black|clamp|periodic|mirror" ]]
```
"mapper"
: A pop-up with associative choices (an enumerated type, if the values are
integers). This widget further requires parameter metadata `options`, a
`|`-delimited string with "key:value" pairs. For example:
```
int pattern = 0
[[ string widget = "mapper",
string options = "oak:0|elm:1|walnut:2" ]]
```
"filename"
: A file selection dialog.
"null"
: A hidden widget.
float min, float max, int min, int max
: The minimum and/or maximum value that the parameter may take on.
float sensitivity, int sensitivity
: The precision or step size for incrementing or decrementing the value
(within the appropriate min/max range).
int digits
: The number of digits to show (-1 for full precision).
int slider
: If nonzero, enables display of a slider sub-widget. This also respects the
following additional metadata that control the slider specifically:
`slidermin` (minimum value for the slider, `slidermax` (maximum value for
the slider), `slidercenter` (origin value for the slider), `sliderexponent`
(nonlinear slider options).
string URL
: Provides a URL for full documentation of the shader or parameter.
string units
: Gives the assumed units, if any, for the parameter (e.g., `cm`, `sec`,
`degrees`). The compiler or renderer may issue a warning if it detects that
this assumption is being violated (for example, the compiler can warn if a
`degrees` variable is passed as the argument to `cos`).
% We never implemented this:
% ## Public methods
%
% Ordinary (non-public) functions inside a shader may be called only from
% within the shader; they do not generate entry points that the renderer
% is aware of.
%
% A *public method* is a function that may be directly called by the
% renderer. Only top-level local functions of a shader --- that is,
% declared within the braces that define the local scope of the shader,
% but not within any other such function --- may be public methods. A
% function may be designated a public method by using the `public`
% keyword immediately before the function declaration:
%
% > *shader-type shader-name* `(` *params* `)` \
% > `{` \
% >
% > `public` *return-type* *function-name* `(` *optional-parameters* `)` \
% > `{` \
% > *statements* \
% > `}` \
% >
% > ...\\
% > `}`
% A given renderer will publish a list of public methods (names, arguments
% expected, and return value) that has particular meaning for that
% renderer. For example, a renderer may honor a public method
% ```
% public float maxdisplacement ()
% ```
% that computes and returns the maximum distance
% that a displacement shader will move any surface points.
% At some later point, this spec will recommend several ``standard''
% public methods that should be honored by most renderers.
+83
View File
@@ -0,0 +1,83 @@
..
Copyright Contributors to the Open Shading Language project.
SPDX-License-Identifier: CC-BY-4.0
.. image::
../../ASWF/logos/openshadinglanguage-stacked-Shaded.png
=============================================
Open Shading Language |version| Documentation
=============================================
.. only:: not latex
Editor: Larry Gritz, OSL Chief Architect
Open Shading Language (OSL) is a small but rich language for programmable
shading in advanced renderers and other applications, ideal for describing
materials, lights, displacement, and pattern generation.
Quick Links:
`GitHub repository <https://github.com/AcademySoftwareFoundation/OpenShadingLanguage>`_ /
`Developer mail list <https://lists.aswf.io/g/osl-dev>`_ /
`BSD License <https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/blob/master/LICENSE.md>`_
------------
.. default-role:: code
.. only:: not latex
Contents
--------
.. toctree::
:caption: Introduction
copyr
.. toctree::
:caption: The OSL Language Specification
:maxdepth: 2
:numbered: 2
intro
bigpicture
lexical
grosssyntax
datatypes
syntax
stdlib
grammar
shadergroups
glossary
.. comment
This is where we would put additional documentation sections
in the future.
.. comment
Helpful links when writing documentation:
Doxygen docs:
http://www.doxygen.nl/manual/index.html
Sphinx docs:
http://www.sphinx-doc.org/en/master/contents.html
http://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#cpp-domain
Breathe docs:
https://github.com/michaeljones/breathe
https://breathe.readthedocs.io/en/latest/directives.html
RST:
sphinx-tabs plugin for Sphinx:
https://pypi.org/project/sphinx-tabs/
https://sphinx-tabs.readthedocs.io/en/latest/#
+193
View File
@@ -0,0 +1,193 @@
<!--
Copyright Contributors to the Open Shading Language project.
SPDX-License-Identifier: CC-BY-4.0
SPDX-License-Identifier: BSD-3-Clause
-->
(chap-introduction=)
# Introduction
Welcome to Open Shading Language!
Open Shading Language (OSL) is a small but rich language for
programmable shading in advanced renderers and other applications, ideal
for describing materials, lights, displacement, and pattern generation.
OSL was developed by Sony Pictures Imageworks for use in its in-house
renderer used for feature film animation and visual effects. The
language specification was developed with input by other visual effects
and animation studios who also wish to use it.
OSL is distributed under the "New BSD" license. In short, you are free
to use it in your own applications, whether they are free or commercial,
open or proprietary, as well as to modify the OSL code as you desire,
provided that you retain the original copyright notices as described in
the license.
#### How OSL is different from other shading languages
OSL has syntax similar to C, as well as other shading languages.
However, it is specifically designed for advanced rendering algorithms
and has features such as radiance closures, BSDFs, and deferred ray
tracing as first-class concepts.
OSL has several unique characteristics not found in other shading
languages (certainly not all together). Here are some things you will
find are different in OSL compared to other languages:
* **Surface and volume shaders compute radiance closures, not final colors.**
OSL's surface and volume shaders compute an explicit symbolic
description, called a "closure," of the way a surface or volume
scatters light, in units of radiance. These radiance closures may be
evaluated in particular directions, sampled to find important
directions, or saved for later evaluation and re-evaluation.
This new approach is ideal for a physically-based renderer that
supports ray tracing and global illumination.
In contrast, other shading languages usually compute just a surface
color as visible from a particular direction. These old shaders are
"black boxes" that a renderer can do little with but execute to for
this once piece of information (for example, there is no effective way
to discover from them which directions are important to sample).
Furthermore, the physical units of lights and surfaces are often
underspecified, making it very difficult to ensure that shaders are
behaving in a physically correct manner.
* **Surface and volume shaders do not loop over lights or shoot rays.**
There are no "light loops" or explicitly traced rays in OSL surface
shaders. Instead, surface shaders compute a radiance closure
describing how the surface scatters light, and a part of the renderer
called an "integrator" evaluates the closures for a particular set of
light sources and determines in which directions rays should be
traced. Effects that would ordinarily require explicit ray tracing,
such as reflection and refraction, are simply part of the radiance
closure and look like any other BSDF.
Advantages of this approach include that integration and sampling may
be batched or re-ordered to increase ray coherence; a "ray budget" can
be allocated to optimally sample the BSDF; the closures may be used by
for bidirectional ray tracing or Metropolis light transport; and the
closures may be rapidly re-evaluated with new lighting without having
to re-run the shaders.
* **Surface and light shaders are the same thing.**
OSL does not have a separate kind of shader for light sources. Lights
are simply surfaces that are emissive, and all lights are area lights.
* **Transparency is just another kind of illumination.**
You don't need to explicitly set transparency/opacity variables in the
shader. Transparency is just another way for light to interact with a
surface, and is included in the main radiance closure computed by a
surface shader.
* **Renderer outputs (AOV's) are specified using "light path expressions."**
Sometimes it is desirable to output images containing individual
lighting components such as specular, diffuse, reflection, individual
lights, etc. In other languages, this is usually accomplished by
adding a plethora of "output variables" to the shaders that collect
these individual quantities.
OSL shaders need not be cluttered with any code or output variables to
accomplish this. Instead, there is a regular-expression-based
notation for describing which light paths should contribute to which
outputs. This is all done on the renderer side (though supported by
the OSL implementation). If you desire a new output, there is no need
to modify the shaders at all; you only need to tell the renderer the
new light path expression.
* **Shaders are organized into networks.**
OSL shaders are not monolithic, but rather can be organized into
networks of shaders (sometimes called a shader group, graph, or DAG),
with named outputs of some nodes being connected to named inputs of
other nodes within the network. These connections may be done
dynamically at render time, and do not affect compilation of
individual shader nodes. Furthermore, the individual nodes are
evaluated lazily, only their outputs are "pulled" from the later nodes
that depend on them (shader writers may remain blissfully unaware of
these details, and write shaders as if everything is evaluated
normally).
* **No "uniform" and "varying" keywords in the language.**
OSL shaders are evaluated in SIMD fashion, executing shaders on many
points at once, but there is no need to burden shader writers with
declaring which variables need to be uniform or varying.
In the open source OSL implementation, this is done both automatically
and dynamically, meaning that a variable can switch back and forth
between uniform and varying, on an instruction-by-instruction basis,
depending on what is assigned to it.
* **Arbitrary derivatives without grids or extra shading points.**
In OSL, you can take derivatives of any computed quantity in a shader,
and use arbitrary quantities as texture coordinates and expect correct
filtering. This does not require that shaded points be arranged in a
rectangular grid, or have any particular connectivity, or that any
"extra points" be shaded.
In the open source OSL implementation, this is possible because
derivatives are not computed by finite differences with neighboring
points, but rather by "automatic differentiation," computing partial
differentials for the variables that lead to derivatives, without any
intervention required by the shader writer.
## Acknowledgments
The original designer and project leader of OSL is Larry Gritz. Other early
developers of OSL are (in order of joining the project): Cliff Stein, Chris
Kulla, Alejandro Conty, Jay Reynolds, Solomon Boulos, Adam Martinez, Brecht
Van Lommel.
Additionally, many others have contributed features, bug fixes, and other
changes: Steve Agland, Shane Ambler, Martijn Berger, Farchad Bidgolirad,
Nicholas Bishop, Stefan Büttner, Matthaus G. Chajdas, Thomas Dinges, Henri
Fousse, Syoyo Fujita, Derek Haase, Sven-Hendrik Haase, John Haddon, Daniel
Heckenberg, Ronan Keryell, Elvic Liang, Max Liani, Bastien Montagne, Erich
Ocean, Mikko Ohtamaa, Alex Schworer, Sergey Sharybin, Stephan Steinbach,
Esteban Tovagliari, Alexander von Knorring, Roman Zulak. (Listed
alphabetically; if we've left anybody out, please let us know.)
We cannot possibly express sufficient gratitude to the managers at Sony
Pictures Imageworks who allowed this project to proceed, supported it
wholeheartedly, and permitted us to release the source, especially Rob
Bredow, Brian Keeney, Barbara Ford, Rene Limberger, and Erik Strauss.
Huge thanks also go to the crack shading team at SPI, and the brave
lookdev TDs and CG supes willing to use OSL on their shows. They served
as our guinea pigs, inspiration, testers, and a fantastic source of
feedback. Thank you, and we hope we've been responsive to your needs.
OSL was not developed in isolation. We owe a debt to the individuals
and studios who patiently read early drafts of the language
specification and gave us very helpful feedback and additional ideas,
and especially to those at other companies who have taken the risk of
incorporating OSL into their products and pipelines.
The open source OSL implementation incorporates or depends upon several
other open source packages:
- **OpenImageIO** Copyright Contributors to OpenImageIO.
http://openimageio.org
- **Imath** Copyright Contributors to Imath.
http://www.openexr.com
- **Boost** Copyright various authors. http://www.boost.org
- **LLVM** Copyright 2003-2010 University of Illinois at
Urbana-Champaign. http://llvm.org
These other packages are all distributed under licenses that allow them
to be used by and distributed with OSL.
+122
View File
@@ -0,0 +1,122 @@
# Lexical structure
## Characters
Source code for OSL consists of ASCII or UTF-8 characters.
The characters for space, tab, carriage return, and linefeed are
collectively referred to as *whitespace*. Whitespace characters
delimit identifiers, keywords, or other symbols, but other than that
have no syntactic meaning. Multiple whitespace characters in a row
are equivalent to a single whitespace character.
Source code may be split into multiple lines, separated by end-of-line
markers (carriage return and/or linefeed). Lines may be of any length
and end-of-line markers carry no significant difference from other
whitespace, except that they terminate `//` comments and delimit
preprocessor directives.
## Identifiers
*Identifiers* are the names of variables, parameters, functions, and shaders.
In OSL, identifiers consist of one or more characters. The first character
may be a letter (`A`-`Z` or `a`-`z`) or underscore (`_`), and subsequent
characters may be letters, underscore, or numerals (`0`-`9`). Examples of
valid and invalid identifiers are:
```
opacity // valid
Long_name42 // valid - letters, underscores, numbers are ok
_foo // valid - ok to start with an underscore
2smart // invalid - starts with a numeral
bigbuck$ // invalid - $ is an illegal character
```
## Comments
*Comments* are text that are for the human reader of programs, and
are ignored entirely by the OSL compiler. Just like in C++, there
are two ways to designate comments in OSL:
1. Any text enclosed by `/*` and `*/` will be considered a comment, even if
the comment spans several lines.
```
/* this is a comment */
/* this is also
a comment, spanning
several lines */
```
2. Any text following `//`, up to the end of the current line, will be
considered a comment.
```
// This is a comment
a = 3; // another comment
```
## Keywords and reserved words
There are two sets of names that you may not use as identifiers:
keywords and reserved words.
The following are *keywords* that have special meaning in OSL:
and break closure color continue do else emit float for if illuminance
illuminate int matrix normal not or output point public return string
struct vector void while
The following are *reserved words* that currently have no special meaning in
OSL, but we reserve them for possible future use, or because they are
confusingly similar to keywords in related programming languages:
bool case catch char class const delete default double
enum extern false friend
goto inline long new operator private protected
short signed sizeof static
switch template this throw true try typedef
uniform union unsigned varying virtual volatile
## Preprocessor
Shader source code is passed through a standard C preprocessor as a
first step in parsing.
Preprocessor directives are designated by a hash mark `#` as the first
character on a line, followed by a preprocessor directive name. Whitespace may
optionally appear between the hash and the directive name.
OSL compilers support the full complement of C/C++ preprocessing directives,
including:
```
#define
#undef
#if
#ifdef
#ifndef
#elif
#else
#endif
#include
#pragma error "message"
#pragma once
#pragma osl ...
#pragma warning "message"
```
Additionally, the following preprocessor symbols will already be
defined by the compiler:
| | |
| ------ | :------- |
| `OSL_VERSION_MAJOR` | Major version (e.g., 1) |
| `OSL_VERSION_MINOR` | Minor version (e.g., 9) |
| `OSL_VERSION_PATCH` | Patch version (e.g., 3) |
| `OSL_VERSION` | Combined version number = `10000*major + 100*minor + patch` (e.g., 10903 for version 1.9.3) |
+6
View File
@@ -0,0 +1,6 @@
sphinx >= 5.0
breathe == 4.34.0
sphinx-tabs
furo==2022.6.21
myst-parser
linkify
+100
View File
@@ -0,0 +1,100 @@
---
numbering:
heading_1: true
heading_2: true
heading_3: true
---
<!--
Copyright Contributors to the Open Shading Language project.
SPDX-License-Identifier: CC-BY-4.0
-->
(chap-shader-groups)=
# Describing shader groups
Below, we propose a simple grammar giving a standard way to serialize (i.e.,
express as text) a full shader group, including instance values and
connectivity of the shader layers. There are only three statements/operations:
set an instance value, make a shader instance, and connect two instances.
**`param`** *`type paramname value`*... **`;`** <br> **`param`** *`type paramname value`*... **`[[`** *`metadata`*... **`]] ;`**
: Declare an instance value of a shader parameter to be applied to the next
`shader` statement. We refer to the parameter values set, which have not
yet had their shader declared, as *pending parameters*.
The *`paramname`* is the name of the parameter whose instance values are
being specified.
The *`type`* is one of the basic numeric or string data types described in
Chapter [](#chap-types) (`int`, `float`,`color`, `point`, `vector`, `normal`,
`matrix`, or `string`), or an array thereof (indicated by the usual notation
of `[size]`). The *`type`* must match the declared type of the parameter in
the shader.
The actual values are listed individually, with multiple values (in the
case of an array or an aggregate such as a `color`) simply separated by
whitespace. If fewer values are supplied than the total number of array
elements or aggregate components, the remainder will be understood to be
filled with 0 values. String values must be enclosed in double quotes
(`"like this"`).
The `param` statement is terminated by a semicolon (`;`).
Optionally, metadata hints may be supplied enclosed by double brackets,
immediately before the semicolon.
**`shader`** *`shadername layername`* **`;`**
: Declares a shader instance, which will receive any pending parameters that
were declared since the previous `shader` statement (and in the process,
clear the list of pending parameters).
The `shadername` is an identifier that specifies the name of the shader
to use as the master for this instance. The `layername` is an identifier
that names the layer (e.g., to subsequently specify it as a source or
destination for connections).
The `shader` statement is terminated by a semicolon (`;`).
**`connect`** *`source_layername`* **`.`** *`paramname`* $~~$ *` destination_layername`* **`.`** *`paramname`* **`;`**
: Establish a connection between an output parameter of a source layer and an
input parameter of a destination layer, both of which have been previously
declared within this group. The source layer must have preceded the
destination layer when they were declared, and the parameters must exist and
be of a compatible type so that it is meaningful to establish a connection
(for example, you may connect a `color` to a `color`, but you may not connect
a `color` to a `matrix`).
If the named parameters are structures, the two structures must have
identical data layout, and establishing the connection will connect each
corresponding data member. It is also possible to make a connection of just
a single member of a structure by using the usual ``dot'' syntax, for
example, for layers `A` and `B`, `connect A.c.x B.y` might
connect A's parameter `c`, member `x`, to B's parameter `y` (the
types of `c.x` in A and `y` in B must match).
The `connect` statement is terminated by a semicolon (`;`).
**Example**
param string name "rings.tx" ; # set pending `name'
param float scale 3.5 ; # set pending `scale'
shader "texturemap" "tex1" ; # tex1 layer, picks up `name', `scale'
param string name "grain.tx" ;
shader "texturemap" "tex2" ;
param float gam 2.2 ;
shader "gamma" "gam1" ;
param float gam 1.0 ;
shader "gamma" "gam2" ;
param color woodcolor 0.42 0.38 0.22 ; # example of a color param
shader "wood" "wood1" ;
connect tex1.Cout gam1.Cin ; # connect tex1's Cout to gam1's Cin
connect tex2.Cout gam2.Cin ;
connect gam1.Cout wood1.rings ;
connect gam2.Cout wood1.grain ;
+2232
View File
File diff suppressed because it is too large Load Diff
+566
View File
@@ -0,0 +1,566 @@
---
numbering:
heading_1: true
heading_2: true
heading_3: true
---
<!--
Copyright Contributors to the Open Shading Language project.
SPDX-License-Identifier: CC-BY-4.0
-->
(chap-syntax)=
# Language Syntax
The body of a shader is a sequence of individual *statements*.
This chapter describes the types of statements and control-flow patterns
in OSL.
Statements in OSL include the following types of constructs:
* Scoped statements.
* Variable declarations.
* Expressions.
* Assignments.
* Control flow: `if`, `else`, `while`, `do`, `for`, `break`, `continue`
* Function declarations.
#### Scoping
Any place where it is legal to have a statement, it is legal to have multiple
statements enclosed by curly braces `{ }`. This is called a *scope*. Any
variables or functions declared within a scope are only visible within that
scope, and only may be used after their declaration. Variables or functions
that are referenced will always resolve to the matching name in the innermost
scope relative to its use. For example
```
float a = 1; // Call this the "outer" 'a'
float b = 2;
{
float a = 3; // Call this the "inner" 'a'
float c = 1;
b = a; // b gets 3, because a is resolved to the inner scope
}
b += c; // ERROR -- c was only in the inner scope
```
## Variable declarations and assignments
### Variable declarations
The syntax for declaring a variable in OSL is:
> *type* *name*
>
> *type* *name* `=` *value*
where
* *type* is one of the basic data types, described earlier.
* *name* is the name of the variable you are declaring.
* If you wish to initialize your variable an initial value, you may
immediately assign it a *value*, which may be any valid expression.
You may declare several variables of the same type in a single
declaration by separating multiple variable names by commas:
> *type* *name1* `,` *name2* ...
>
> *type* *name1* [ = *value1*] `,` *name2* [ `=` *value2* ] ...
Some examples of variable declarations are
```
float a; // Declare; current value is undefined
float b = 1; // Declare and assign a constant initializer
float c = a*b; // Computed initializer
float d, e = 2, f; // Declare several variables of the same type
```
### Arrays
Arrays are also supported, declared as follows:
> *type variablename* `[` *arraylen* `}`
>
> *type variablename* `[` *arraylen* `}` `=` `{` *init0 `,` *init1* ... `}`
Array variables in OSL must have a constant length (though function parameters
and shader parameters may have undetermined length). Some examples of array
variable declarations are:
```
float d[10]; // Declare an uninitialized array
float c[3] = { 0.1, 0.2, 3.14 }; // Initialize the array
```
### Structures
Structures are used to group several fields of potentially different
types into a single object that can be referred to by name. The syntax
for declaring a structure type is:
\spc `struct` *structname* {\cf \{}
\spc\spc *type1* *fieldname1* `;`
\spc\spc ...
\spc\spc *typeN* *fieldnameN* `;`
\spc `) ;`
You may then use the structure type name to declare structure variables
as you would for any of the built-in types:
\spc *structname* *variablename* `;`
\spc *structname* *variablename* {\cf = \{ }
*initializer1* `,` ... *initializerN* `) ;`
If initializers are supplied, each field of the structure will be
initialized with the initializer in the corresponding position, which
is expected to be of the appropriate type.
Structure elements are accessed in the same way as other C-like
languages, using the `dot' operator:
\spc *variablename*{\cf .} *fieldname*
Examples of declaration and use of structures:
```
struct ray {
point pos;
vector dir;
};
ray r; // Declare a structure
ray s = { point(0,0,0), vector(0,0,1) }; // declare and initialize
r.pos = point (1, 0, 0); // Assign to one field
```
It is permitted to have a structure field that is an array, as well as
to have an array of structures. But it is not permitted for one
structure to have a field that is another structure.
Please refer to Section~\ref{sec:types:struct} for more information
on using `struct`.
(sec-expressions)=
## Expressions
The expressions available in OSL include the following:
* Constants: integer (e.g., `1`, `42`), floating-point (e.g. `1.0`, `3`,
`-2.35e4`), or string literals (e.g., `"hello"`)
* point, vector, normal, or matrix constructors, for example:
```
color (1, 0.75, 0.5)
point ("object", 1, 2, 3)
```
If all the arguments to a constructor are themselves constants, the
constructed point is treated like a constant and has no runtime cost.
That is, `color(1,2,3)` is treated as a single constant entity, not
assembled bit by bit at runtime.
* Variable or parameter references
* An individual element of an array (using `[ ]`)
* An individual component of a `color`, `point`, `vector`, `normal` (using
`[ ]`), or of a `matrix` (using `[][]`)
* prefix and postfix increment and decrement operators:
Operator | Meaning
:-- | :--
*varref* `++` | post-increment
*varref* `--` | post-decrement
`++` *varref* | pre-increment
`--` *varref* | pre-decrement
The post-increment and post-decrement (e.g., {\cf a++}) returns the old
value, then increments or decrements the variable; the pre-increment and
pre-decrement ({\cf ++a}) will first increment or decrement the
variable, then return the new value.
* Unary and binary arithmetic operators on other expressions:
Operator | Meaning
:-- | :--
`-` *expr* | negation
`~` *expr* | bitwise complement
*expr* `*` *expr* | multiplication
*expr* `/` *expr* | division
*expr* `+` *expr* | addition
*expr* `-` *expr* | subtraction
*expr* `%` *expr* | integer modulus
*expr* `<<` *expr* | integer shift left
*expr* `>>` *expr* | integer shift right
*expr* `&` *expr* | bitwise and
*expr* `\|` *expr* | bitwise or
*expr* `^` *expr* | bitwise exclusive or
The operators `+`, `-`, `*`, `/`, and the unary `-` (negation) may be used
on most of the numeric types. For multicomponent types (`color`, `point`,
`vector`, `normal`, `matrix`), these operators combine their arguments on a
component-by-component basis. The only operators that may be applied to the
`matrix` type are `*` and `/`, which respectively denote matrix-matrix
multiplication and matrix multiplication by the inverse of another matrix.
The integer and bit-wise operators `%`, `<<`, `>>`, `&`, `|`, `^`, and `~`
may only be used with expressions of type `int`.
For details on which operators are allowed, please consult the operator
tables for each individual type in Chapter [](#chap-types).
* Relational operators (all lower precedence than the arithmetic operators):
Operator | Meaning
:-- | :--
*expr* `==` *expr* | equal to
*expr* `!=` *expr* | not equal to
*expr* `<` *expr* | less then
*expr* `<=` *expr* | less than or equal to
*expr* `>` *expr* | greater than
*expr* `>=` *expr* | greater than or equal
The `==` and `!=` operators may be performed between any two values of equal
type, and are performed component-by-component for multi-component types.
The `<`, `<=`, `>`, `>=` may not be used to compare multi-component types.
An `int` expression may be compared to a `float` (and is treated as if
they are both `float`). A `float` expression may be compared to a
multi-component type (and is treated as a multi-component type as if
constructed from a single float).
Relation comparisons produce Boolean (true/false) values. These
are implemented as `int` values, 0 if false and 1 if true.
* Logical unary and binary operators:
> `!` *expr*
> *expr1* `&&` *expr2*
> *expr1* `\|\|` *expr2*
Note that the `not`, `and`, and `or` keywords are synonyms for `!`, `&&`,
and `||`, respectively.
For the logical operators, numeric expressions (`int` or `float`) are
considered *true* if nonzero, *false* if zero. Multi-component types (such
as `color`) are considered *true* any component is nonzero, *false* all
components are zero. Strings are considered *true* if they are nonempty,
*false* if they are the empty string (`""`).
* another expression enclosed in parentheses: `( )`. Parentheses may be used
to guarantee associativity of operations.
* Type casts, specified either by having the type name in parentheses in front
of the value to cast (C-style typecasts) or the type name called as a
constructor (C++-style type constructors):
```
(vector) P /* cast a point to a vector */
(point) f /* cast a float to a point */
(color) P /* cast a point to a color! */
vector (P) /* Means the same thing */
point (f)
color (P)
```
The three-component types (`color`, `point`, `vector`, `normal`) may be cast
to other three-component types. A `float` may be cast to any of the
three-component types (by placing the float in all three components) or to a
`matrix` (which makes a matrix with all diagonal components being the
`float`). Obviously, there are some type casts that are not allowed because
they make no sense, like casting a `point` to a `float`, or casting a
`string` to a numerical type.
* function calls
* assignment expressions:
same thing as `var = var OP expr` :
Operator | Meaning
:-- | :--
*var* `=` *expr* | assign
*var* `+=` *expr* | add
*var* `-=` *expr* | subtract
*var* `*=` *expr* | multiply
*var* `/=` *expr* | divide
*int-var* `&=` *int-expr* | bitwise and
*int-var* `\|=` *int-expr* | bitwise or
*int-var* `^=` *int-expr* | bitwise exclusive or
*int-var* `<<=` *int-expr* | integer shift left
*int-var* `>>=` *int-expr* | integer shift right
Note that the integer and bit-wise operators are only allowed with `int`
variables and expressions. In general, `var OP= expr` is allowed only if
`var = var OP expr` is allowed, and means exactly the same thing. Please
consult the operator tables for each individual type in Chapter
[](#chap-types).
* ternary operator, just like C:
> *condition* `?` *expr1* `:` *expr2*
This expression takes on the value of *expr1* if *condition* is true
(nonzero), or *expr2* if *condition* is false (zero).
Please refer to Chapter [](#chap-types), where the section describing each
data type describes the full complement of operators that may be used with the
type. Operator precedence in OSL is identical to that of C.
## Control flow: `if`, `while`, `do`, `for`
Conditionals in OSL just like in C or C++:
\begin{tabbing}
\hspace{0.5in} \= \hspace{0.3in} \= \kill
\> {\cf if (} *condition* {\cf )} \\
\> \> *truestatement*
\end{tabbing}
and
\begin{tabbing}
\hspace{0.5in} \= \hspace{0.3in} \= \kill
\> {\cf if (} *condition* {\cf )} \\
\> \> *truestatement* \\
\> {\cf else} \\
\> \> *falsestatement*
\end{tabbing}
The statements can also be entire blocks, surrounded by curly
braces. For example,
```
if (s > 0.5) {
x = s;
y = 1;
} else {
x = s+t;
}
```
The *condition* may be any valid expression, including:
* The result of any comparison operator (such as `<`, `==`, etc.).
* Any numeric expression (`int`, `color`, `point`, `vector`, `normal`,
`matrix`), which is considered "true" if nonzero and "false" if zero.
* Any string expression, which is considered "true" if it is a nonempty
string, "false" if it is the empty string (`""`).
* A closure, which is considered "true" if it's empty (not assigned, or
initialized with {\cf =0}), and "false" if anything else has been assigned
to it.
* A logical combination of expressions using the operators `!` (not), `&&`
(logical "and"), or `||` (logical "or"). Note that `&&` and `\|\|`
*short circuit* as in C, i.e. `A && B` will only evaluate B if A
is true, and `A || B` will only evaluate B if A is false.
Repeated execution of statements for as long as a condition is true is
possible with a `while` statement:
> `while (` *condition* `)` *statements*
Or the test may happen after the body of the loop, with a `do/while` loop:
> `do` *statement* `while (` *condition* `)`
Also, `for` loops are also allowed:
> `for (` *initialization-statement* `;` *condition* `;` *iteration-statement* `)` \
> *body-statements*
As in C++, a `for` loop's initialization may contain variable declarations and
initializations, which are scoped locally to the `for` loop itself. For
example,
```
for (int i = 0; i < 3; ++i) {
...
}
```
As with `if` statements, loop conditions may be relations or numerical
quantities (which are considered "true" if nonzero, "false" if zero), or
strings (considered "true" if nonempty, "false" if the empty string `""`.
Inside the body of a loop, the `break` statement terminates the loop
altogether, and the `continue` statement skip to the end of the body and
proceeds to the next iteration of the loop.
## Functions
### Function definitions
You may define functions much like in C or C++.
> *return-type* *function-name* `(` *optional-parameters* `)` \
> `{` \
> *statements* \
> `}`
Parameters to functions are similar to shader parameters, except that they do
not permit initializers. A function call must pass values for all formal
parameters. Function parameters in OSL are all *passed by reference*, and are
read-only within the body of the function unless they are also designated as
`output` (in the same manner as output shader parameters).
Like for shaders, statements inside functions may be actual executions
(assignments, function call, etc.), local variable declarations (visible
only from within the body of the function), or local function
declarations (callable only from within the body of the function).
The return type may be any simple data type, a `struct`, or a
`closure`. Functions may not return arrays. The return type may be
`void`, indicating that the function does not return a value (and
should not contain a `return` statement). A `return` statement
inside the body of the function will halt execution of the function at
that point, and designates the value that will be returned (if not a
`void` function).
Functions may be *overloaded*. That is, multiple functions may be
defined to have the same name, as long as they have differently-typed
parameters, so that when the function is called the list of arguments can
select which version of the function is desired. When there are multiple
potential matches, function versions whose argument types match exactly are
favored, followed by those that match with type coercion (for example,
passing an `int` when the function expects a `float`, or passing a
`float` when the function expects a `color`), and finally by trying to
match the return value to the type of variable the result is assigned to.
(sec-syntax-functioncalls)=
### Function calls
Function calls are very similar to C and related programming languages:
> *functionname* `(` *arg1* `,` ... `,` *argn* `)`
If the function returns a value (not `void`), you may use its value as an
expression. It is fine to completely ignore the value of even a non-`void`
function.
In OSL, all arguments are passed by reference. This generally will not be
noticeably different from C-style "pass by value" semantics, except if you
pass the same variable as two separate arguments to a function that modifies
an argument's value.
Certain functions allow optional arguments to be passed.
Optional arguments are key-value pairs with the key passed as an argument and
the associated value passed as the subsequent argument:
> *functionname* `(` *arg1* `,` ... `,` *argn* `,` *"optionalkey"* `,` *optionalvalue* `,` ... `)`
### Operator overloading
OSL permits \emph{operator overloading}, which is the practice of providing a
function that will be called when you use an operator like `+` or `*`. This is
especially handy when you use `struct` to define mathematical types and wish
for the usual math operators to work with them. Here is a typical example,
which also shows the special naming convention that allows operator
overloading:
```
struct vector4 {
float x, y, z, w;
};
vector4 __operator__add__ (vector4 a, vector4 b) {
return vector4 (a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w);
}
shader test ()
{
vector4 a = vector4 (.2, .3, .4, .5);
vector4 b = vector4 (1, 2, 3, 4);
vector4 c = a + b; // Will call __operator__add__(vector4,vector4)
printf ("a+b = %g %g %g %g\n", c.x, c.y, c.z, c.w);
}
```
The full list of these special function names is as follows (in order of
decreasing operator precedence):
Operator | Overload function name | notes
:---------- | :----------- | :------
`-` | `__operator__neg__` | unary negation
`~` | `__operator__compl__` | unary bitwise
`!` | `__operator__not__` | unary boolean 'not'
`*` | `__operator__mul__` |
`/` | `__operator__div__` |
`\%` | `__operator__mod__` |
`+` | `__operator__add__` |
`-` | `__operator__sub__` |
`<<` | `__operator__shl__` |
`>>` | `__operator__shr__` |
`<` | `__operator__lt__` |
`<=` | `__operator__le__` |
`>` | `__operator__gt__` |
`>=` | `__operator__ge__` |
`==` | `__operator__eq__` |
`!=` | `__operator__ne__` |
`\&` | `__operator__bitand__` |
`^` | `__operator__xor__` |
`\|` | `__operator__bitor__` |
## Global variables
*Global variables* (sometimes called *graphics state variables*) contain the
basic information that the renderer knows about the point being shaded, such
as position, surface orientation, and default surface color. You need not
declare these variables; they are simply available by default in your shader.
Global variables available in shaders are listed in the following table:
Variable | Description
:---------- | :-----------
`point P` | Position of the point you are shading. In a displacement shader, changing this variable displaces the surface.
`vector I` | The *incident* ray direction, pointing from the viewing position to the shading position `P`.
`normal N` | The surface "Shading" "normal of the surface at `P`. Changing `N` yields bump mapping.
`normal Ng` | The true surface normal at `P`. This can differ from `N`; `N` can be overridden in various ways including bump mapping and user-provided vertex normals, but `Ng` is always the true surface geometric normal of the surface at `P`.
`float u, v` | The 2D parametric coordinates of \P (on the particular geometric primitive you are shading).
`vector dPdu, dPdv` | Partial derivatives $\partial P/\partial u$ and $\partial P/\partial v$ tangent to the surface at `P`.
`point Ps` | Position at which the light is being queried (currently only used for light attenuation shaders)
`float time` | Current shutter time for the point being shaded.
`float dtime` | The amount of time covered by this shading sample.
`vector dPdtime` | How the surface position \P is moving per unit time
`closure color Ci` | Incident radiance --- a closure representing the color of the light leaving the surface from `P` in the direction `-I`.
Accessibility of variables by shader type:
Variable | surface | displacement | volume
:---------- | ----- | -- | --
`P` | R | RW | R
`I` | R | | R
`N` | RW | RW |
`Ng` | R | R |
`dPdu` | R | R |
`dPdv` | R | R |
`Ps` | | | R
`u, v` | R | R | R
`time` | R | R | R
`dtime` | R | R | R
`dPdtime` | R | R | R
`Ci` | RW | | RW