Photon 2.0.0-beta
A physically based renderer.
Loading...
Searching...
No Matches
Scene Description Guide

Here, you will learn about the scene description language used in Photon, sometimes referred to as PSDL (Photon Scene Description Language). It is a special format created for storing scene data as well as controlling the behavior of the render engine. We also have API generators for different programming languages, allowing users to programmatically build scene descriptions and output customized formats for various applications. The reference for all engine features exposed as PSDL can be found here.

Introduction

Let us first see how a simple scene would be represented in PSDL. The hello-world scene that will be rendered by Photon looks like this

Rendered hello-world scene.

This image can be generated by feeding the following descriptions into Photon:

observer(single-lens) @observer = [real fov-degrees 30] [vector3 pos "0 6 40"] [vector3 dir "0 0 -1"] [vector3 up-axis "0 1 0"];
sample-source(stratified) @sampler = [integer samples 10];
visualizer(path-tracing) @visualizer = [enum sample-filter gaussian][enum estimator bneept];
option(single-frame-render-session) @session = [vector2 frame-size "512 512"] [string visualizer @visualizer] [string observer @observer] [string sample-source @sampler];
geometry(rectangle) @plane = [real width 15] [real height 15];
geometry(sphere) @ball = [real radius 2.5];
image(constant) @white = [real-array values 0.9];
material(matte-opaque) @diffuse = [image albedo @white];
actor(model) @ground = [geometry geometry @plane] [material material @diffuse];
actor(model).rotate(@ground) = [vector3 axis "1 0 0"] [real degrees -90];
actor(model).scale(@ground) = [vector3 amount "10 10 10"];
actor(model) @object = [geometry geometry @ball] [material material @diffuse];
actor(model).translate(@object) = [vector3 amount "0 2.5 0"];
actor(rectangle-light) @topLight = [spectrum color "1 1 0.8"] [real watts 400] [real width 2] [real height 2];
actor(light).translate(@topLight) = [vector3 amount "0 10 0"];
actor(light).rotate(@topLight) = [vector3 axis "1 0 0"] [real degrees 90];
Note
More example scenes can be found in the ./scenes/ folder in the GitHub repository.

Scene descriptions can be stored in a text file (.p2 filename extension) and loaded by Photon for rendering. Without getting into too much details, the scene description shown above can be summarized as:

  • Declaring a render session:
    • An "observer" to view the scene
    • A "sampler" to provide randomness for numerical integration
    • A "visualizer" to draw the scene from the observer's point of view
  • Declaring data:
    • A 15 m x 15 m plane
    • A ball with 2.5 m radius
    • A white material
  • Placing objects in the scene:
    • We can create a "ground" object by combining the plane and white material. Photon's default coordinate system is right-handed, y-up, x-right. Since a rectangle geometry faces +z by default, a series of transformations are required to place the ground object with the desired rotation and scale.
    • Place a spherical object on the ground
    • Finally, a 400 W rectangular light is placed above the spherical object

After saving the scene description as hello_world.p2 under the build/install directory, you can run the following command in the same directory to render the scene as described:

./bin/PhotonCLI -s ./hello_world.p2 -t 8
Note
Most components of Photon expect the build/install directory to be their working directory, not the directory that contains the executable.

Language Basics

PSDL is a command-like system and the commands can be roughly categorized into two parts: header and clause. Commands are normally structured in the following way:

type-category(type-name) @name = clauses;

where = is the token that separates the header and clauses, which can be naturally interpreted as assigning the RHS clauses into the LHS resource denoted by name. For example, to create a unit-sized rectangle, we write:

geometry(rectangle) @plane = [real width 1] [real height 1];

geometry(rectangle) is the full type information for a geometry resource. By specifying the type name rectangle in the parantheses after geometry, we are creating a rectangle geometry named plane. Its dimension properties are specified via the two square-bracket enclosed clauses that follow the assignment token. In most cases, a clause contains three space-separated parts: a type, a name and a value. A clause is the most fundamental data block in PSDL, and multiple clauses form a SDL data packet. In the example of creating a unit-sized rectangle, [real width 1] [real height 1] is the data packet for initializing the geometry resource named plane. Now, the intention of the following line should be quite obvious:

geometry(sphere) @ball = [real radius 2.5];

It creates a geometry resource named ball, which is a sphere with radius = 2.5. We will dive further into the topics of type and clause later.

As you may have noticed, all commands end with a trailing semi-colon. To disable a command or write a comment, simply put two slashes before the line:

// These commands are being disabled
//sample-source(stratified) @sampler = [integer samples 10];
//actor(model).scale(@ground) = [vector3 amount "10 10 10"];
Note
As long as you do not break any keyword or symbol of PSDL, a single command can be dissected into multiple lines. Cramming multiple commands into a single line is also supported.

In the next sections, we will formally introduce the syntactic structures of PSDL commands.

Type Category

type-category(type-name) @name = clauses;

Describes the category to which the current command belongs. For example, the command that creates a geometry states that its category is geometry in its type category section. There are many categories in PSDL. In addition to the ones seen in the above hello-world scene description, we also have image, object and much more.

Type Name

type-category(type-name) @name = clauses;

Type names generally add details to the type category. Again, in the command that creates a geometry, we know that we are now creating a rectangle geometry from the command fragment geometry(rectangle). Type category and type name are often combined and are called full type name together. Full type name is only needed if the underlying engine operation requires it (such as creating a resource). For executor calls (see the later section), type name can be omitted (will be automatically deduced from the referenced resource) sometimes.

Data Name

type-category(type-name) @name = clauses;

The data name is the name given to the command (e.g., as a resource name, or a reference name) and is always prefixed by @. Note that @ is part of the syntax rather than part of the name. Also, names with whitespace characters should be enclosed by double quotes, see the following example to understand more clearly:

// @ is part of the syntax and should be left out of the double quotes. In this
// example, we created a sphere named "ball name with spaces".
geometry(sphere) @"ball name with spaces" = [real radius 2.5];
actor(model) @balloon = [geometry geometry @"ball name with spaces"];

Clauses

type-category(type-name) @name = clauses;

Clause is a structure that stores parameters for a command. It has the following form:

[type-category parameter-name:tag values]

It is worth pointing out that the parameter-name does not need to start with @. The values section can have many forms such as numerical values (as seen earlier), arrays, and even stand-alone data files (we call them PSDL Resource Identifier). Details for resource identifiers will be introduced in later part of the guide.

// By writing these, we now added a plane, a ball and a material to the scene!
// At this stage, they are like props and are not visible. They still need
// actors to show up in the rendered scene.
geometry(rectangle) @plane = [real width 15] [real height 15];
geometry(sphere) @ball = [real radius 2.5];
image(constant) @white = [real-array values 0.9];
material(matte-opaque) @diffuse = [image albedo @white];

When defining a clause, type-category can be classified into value and reference. Value types do not share data and create a new block of data each time a clause is instantiated. On the other hand, reference types can share their data by instance names, with automatic reference counting.

Value Types

These are common value types* used in a SDL clause:

Type Value Syntax Notes
integer An optionally double-quoted single integer literal. 42, "6789" are all valid inputs. Hexadecimal input like 0xFF is also supported. Internally, the clause may bind to a lower precision field such as uin16. Incompatible value literals will be detected and reported.**
real An optionally double-quoted single floating-point literal. -123, "3.1415926" are all valid literals. Internally, the clause may bind to a field with a type different from float. Incompatible value literals will be detected and reported.**
bool true, True, or TRUE for true; false, False, or FALSE for false.
string A string without whitespaces can be specified directly like nospace. Whitespaces like spaces, tabs, etc. can be included using double quotes like " lots of spaces ".
vector2 Two floating-point literals enclosed by a pair of double quotes. The literals should be separated by whitespace(s) like "-1.2 3.4". If only a single literal is provided, it will be applied to all components. For example, 0.5 is equivalent to "0.5 0.5".
vector3 Similar to vector2, except that three literals are allowed.
vector4 Similar to vector3, except that four literals are allowed.
quaternion Exactly the same as vector4. This type represents a quaternion. For vectors or tuples, use vector4.
real-array Array variant of real that can accept N (N >= 0) floating-point literals. All literals are separated by whitespace(s) and should be enclosed by curly braces. For example, an increasing series of 5 elements can be written as {1.1 2.2 3.3 4.4 5.5}. Accepts resource identifier as input. In this case, it is expected to be a file that contains the value part of the clause.
vector3-array Array variant of vector3 that can accept N (N >= 0) vector3 values. For example, {"7 7 7" "7"} defines two vector3 values, where all components == 7.
path Basically a string, except that its value is interpreted as a filesystem path. It is recommended to use resource identifier where possible so the scene file can be easily distributed without broken links.
enum A string that identifies an enumeration entry. See the scene description reference for valid enumeration identifiers.

All values can be double-quoted unless otherwise noted.

*: Value types do not have type-name. The types shown here are both being full type names and type categories. **: Depending on the settings of the bound field and the parser, such warnings/errors may be disabled.

Reference Types

Each command from the example in the introduction section creates a named reference (if there is a @ specifier* before the name). Consider the following command that creates a rectangle:

geometry(rectangle) @plane = [real width 15] [real height 15];

The reference @plane will uniquely identify the geometry resource, which is a rectangle, that has been created by the command. Many types in PSDL accept references as input. In this case, we use the type-category and a corresponding reference in the clause definition. For example:

image(constant) @white = [real-array values 0.9];
material(matte-opaque) @diffuse = [image albedo @white];

A material resource named diffuse is being created by referencing an image named white as its albedo with the clause [image albedo @white]. Note that references can be used for resource sharing. For example, another diffuse material diffuse2 can be created with the same clause (referencing white) and both diffuse and diffuse2 will be using the same piece of data for their albedo.

*: We call this a persistent specifier. The named target will be persistent throughout the lifetime of the containing scene.

Struct Types

With PSDL, you can create almost all kinds of objects the rendering system has to offer. In later sections, we will see that it is also possible to perform operations on these objects via PSDL.

Operations

Remarks
Go back and check the hello-world scene description again. You should be able to understand most of the lines now.

PSDL Resource Identifier

C++ Binding

Owner Types

Struct Types

Enum Types

Field Types

Function Types

Serialization

Appendix

Full documentation of PSDL commands.