Create a Triangle in Blender and Render it

Create the Triangle

Our first goal looks like this:

A triangle created in Blender

The top line is an area of Blender which is called Info (Python: Area.type). The remaining lower part has a similar line at the bottom and is called 3D viewport. The area inbetween also belongs to the 3D viewport. That area in the middle has + signs on the upper left and right. If you click on them you toggle the visibility of the Tool Shelf (left), or of the Properties (right). The same can be achieved by pressing the left mouse button (LMB) on View in the lower left corner and selecting one of the two last entries (or by the shortcuts mentioned there: T for the Tool Shelf or N for the Properties).

A Clean Start

Let's start with a fresh Blender and first make sure that the factory settings are used. It doesn't really matter how the graphical user interface looks like, you should be able to press the spacebar and start typing factory:

spacebar menu

You should end up with a window like this (see also The Default Screen):

start scene

So, the easiest way to end up with a similar setup as in the first screenshot is to move the mouse into the 3D viewport and press Ctrl-Up Arrow (or press the spacebar again and start typing Toggle Maximize Area).

Get rid of the Default Scene

The default scene consist of a camera, a cube, and a lamp. Let's get rid if them. Press the A key as often (maximum twice) until all objects are selected, then press the X key to delete them.

Turn a Rectangle into a Triangle

Then press 7 followed by 5 on the numeric keypad of your keyboard to end up with the Top Ortho view (the red line shows the x-axis, the green line the y-axis). Press the spacebar and type Add Plane, go into Edit Mode by pressing Tab, select e.g. the upper right vertex by right clicking with your three-button mouse (RMB = right mouse button).

upper right vertex selected

Now Select->Inverse (or press Ctrl-I) followed by X to delete (the three now selected) Vertices. By pressing A you make sure the remaining vertex gets selected.

A little trick to learn about Blender's Python API is to place your mouse cursor at the lower border between the Info area and the 3D viewport until the icon changes to some up-down arrows and drag the area a little bit down to see some lines of Python code, which changes while you work with Blender's user interface. In the screenshot above click (LMB) on the Pivot center for rotation/scaling and make sure it gets changed from Median Point to 3D Cursor. The Python line in question should read like this:

bpy.context.space_data.pivot_point = 'CURSOR'

As a result the 3D manipulator should jump from the selected point to the 3D Cursor (make sure it still is in the origin - x: 0.0, y: 0.0, z: 0.0 - by pressing Shift-C). Let's drag the vertex onto the red line (the x-axis) by pressing S (for scale), Y (along the y-axis), followed by 0 and Enter. Now we are ready to spin the remaining vertex around 360 degrees (using 3 steps) to create our points for the triangle.

bpy.ops.mesh.spin(steps=3, angle=6.28319, center=(0, 0, 0), axis=(0, 0, 1))

spin vertex around 360 degrees

It is interesting to read the info line:

v2.79 | Verts: 1/4 | Edges: 0/3 | Faces 0/0 | Tris: 0 | ... | Plane

We want it to look like this:

v2.79 | Verts: 3/3 | Edges: 3/3 | Faces 1/1 | Tris: 1 | ... | Plane

So, how do we achieve this?

First select all vertices by pressing A twice, then press the spacebar and type Remove Doubles (an alternative is to press W and to select Remove Doubles from the Specials menu).

bpy.ops.mesh.remove_doubles()

Now we got only three vertices, we still have 3 edges, but no faces, nor our single triangle. Simply press F to change that.

bpy.ops.mesh.edge_face_add()

To show the face normal of our triangle we can activate the Properties by pressing N, activate the face normal in Mesh Display (hover over the icons below Normals to see the options), change the size of the normal there, and finally rename the Item from Plane to Triangle.

bpy.context.object.data.show_normal_face = True
bpy.context.scene.tool_settings.normal_size = 0.5
bpy.context.object.name = "Triangle"

To actually see the normal use Ctrl-Spacebar to turn off showing the manipulator, use the middle mouse button (MMB) to turn the Top Ortho view into a User Ortho view, and from there press 5 on the numeric keypad to finally switch to User Persp view. You can use the Home button to zoom in/out and finally you should leave the Edit Mode (by pressing Tab) to switch back to Object Mode.

Render the Triangle

First you need to install the latest version of the Blender add-on mentioned in a previous blog post, called io_scene_pbrt. But how do you install it?

Get the Source Code

The source code is just a Python script and you can clone the repository like this (of course you need git being installed):

# change to a directory of your choice
git clone https://codeberg.org/wahn/Blender
# output
Cloning into 'Blender'...
remote: Counting objects: 167, done.
remote: Compressing objects: 100% (161/161), done.
remote: Total 167 (delta 98), reused 0 (delta 0)
Receiving objects: 100% (167/167), 588.89 KiB | 0 bytes/s, done.
Resolving deltas: 100% (98/98), done.
# go there
cd Blender/
# in fact there are two Python script there
tree io_scene_pbrt/
# output
io_scene_pbrt/
|-- export_pbrt.py
`-- __init__.py

0 directories, 2 files

Install the Blender Add-on

To install the Blender add-on you have to either copy the whole folder or create a symbolic link to it. But first you have to find out where to. I'm assuming that you figured out how to run Blender, so lets learn another bit of Blender and turn the 3D viewport into a Python Console. Simply click on the 3D viewport icon mentioned in the first screenshot on top of this page and select Python Console.

Now you are ready to start typing some Python code. Start by typing bpy and press Ctrl-Space (twice). There should be a dot being added the first time, and the second time your should see a list of sub-modules (e.g. app). Try this:

print(bpy.app.version_string)
print(bpy.app.binary_path)

That should result in something like this:

>>> print(bpy.app.version_string)
2.79 (sub 0)
>>> print(bpy.app.binary_path)
/usr/local/blender-2.79b-linux-glibc219-x86_64/blender

So to copy (or create the symbolic link to) the folder you could use some lines like this (change the paths according to your Python output above):

# copy the whole sub-folder to $BLENDER_VERSION/scripts/addons sub-folder
cp --recursive io_scene_pbrt/ /usr/local/blender-2.79b-linux-glibc219-x86_64/2.79/scripts/addons
# OR create a symbolic link
cd /usr/local/blender-2.79b-linux-glibc219-x86_64/2.79/scripts/addons
ln --symbolic /home/jan/git/codeberg/Blender/io_scene_pbrt .
cd -

If you don't have permissions to write to that location, please follow the instructions in the Blender Manual.

After successful installation your Blender User Preferences (press Ctrl-Alt-U) should look like this (press the Add-ons tab, search for pbrt, activate the add-on):

The add-on being installed

Now you should see a new entry (called PBRT Renderer (.pbrt)) in a list of export scripts if you select File->Export from the Info area.

Export the Scene

So, go ahead and press the PBRT Renderer (.pbrt) button, then navigate to a directory of your choice, choose a name for your .pbrt file, and press the Export PBRT button. Alternatively you can do that from a Python Console too:

>>> bpy.ops.export_scene.pbrt(filepath = "/home/jan/tmp/rs_pbrt/triangle.pbrt")
===============================================================================
bpy.ops.export_scene.pbrt(filepath = "/home/jan/tmp/rs_pbrt/triangle.pbrt")
WARNING: no camera, let me create one for you ;)
WARNING: no light emitters, let me create a point light for you ;)
Point
INFO: /home/jan/tmp/rs_pbrt/triangle.pbrt
WARNING: create new material Triangle_mat
{'FINISHED'}

Wait. What happened? Well, the file triangle.pbrt got exported, but there are also three warnings about a camera, a light, and finally a material being created. So your Blender Outliner window would look like this:

The outliner

The camera got placed above the geometry, so you can see the triangle, and the light got created at the same location. Go ahead and press F12 (or the Render button) to see Blender's internal renderer creating an image of the triangle.

So let's export again:

>>> bpy.ops.export_scene.pbrt(filepath = "/home/jan/tmp/rs_pbrt/triangle.pbrt")
===============================================================================
bpy.ops.export_scene.pbrt(filepath = "/home/jan/tmp/rs_pbrt/triangle.pbrt")
INFO: /home/jan/tmp/rs_pbrt/triangle.pbrt
{'FINISHED'}

... and finally ...

Render with rs-pbrt

Go to the location where the triangle.pbrt got written to and use the rs_pbrt executable to render an image:

# go to location
cd ~/tmp/rs_pbrt
# start rendering
~/git/github/rs_pbrt/target/release/examples/rs_pbrt -i triangle.pbrt
# output
brt version 0.4.4 [Detected 8 cores]
Copyright (c)2016-2018 Jan Douglas Bert Walter.
Rust code based on C++ code by Matt Pharr, Greg Humphreys, and Wenzel Jakob.
Film "image"
  "integer xresolution" [960]
  "integer yresolution" [540]
Sampler "sobol"
  "integer pixelsamples" [8]
Integrator "directlighting"
BVHAccel::recursive_build(..., 1, ...)
PT0.000402396S seconds for building BVH ...
BVHAccel::flatten_bvh_tree(...)
PT0.000003198S seconds for flattening BVH ...
Rendering with 8 thread(s) ...
2040 / 2040 [=========================================================================================================] 100.00 % 1016.96/s
Writing image "pbrt.png" with bounds Bounds2 { p_min: Point2 { x: 0, y: 0 }, p_max: Point2 { x: 960, y: 540 } }

If the resulting image is a bit dark, just raise the energy of the point light in Blender:

bpy.data.lamps['Point'].energy = 10

After that re-export, re-render, and look at the result again:

The resulting image

It should look similar to the image above!