6. Tutorial
This tutorial will show in the first section how to use the
basic features of the CoolRay Language. In the second section,
Basics
In this chapter we will learn how to create a simple Scene.
The CoolRay Language is object oriented. The language distinguishes
between classes and objects. A object is an instance of its class.
E.g. if we want to instanciate a object of the class sphere, we write
the class name followed by a block. A block is marked with curly brackets,
and may have zero, one or more objects, or property assignments inside.
Coordinate System
In order to position our objects, we have to use 3D coordinates.
The coordinate system CoolRay uses, is a so called left-handed
coordinate system. This type of coordinate system is often used
by 3D graphic programs. The positive x-axis points left, the positive
y-axis points up and the z-axis points off.
 |
| CoolRay's Coordinate System |
If we want to specify a point in the 3D space, we use a vector
constant. A vector constant is written as <x, y, z>. The
center would be <0, 0, 0> and <0, 1, 0> would be one
unit above the origin.
Hello World
The easiest possible scene consists of a camera only. This is
not very usefull as there is no object to render:
scene HelloWorld1;
Scene {
PerspectiveCamera {
location := <0, 0, -5>;
}
World {}
}
|
Example 1: HelloWorld1
and how it looks like |
The first element of this scene is the scene name.
This is followed by the scene block.
Inside the Scene Block there is one Camera and one
World object. The camera is located 5 units "behind" the origin
and looks towards the origin. All solids in the World Block can be
visible to the Camera. A solid is a three dimensional geometric
object.
An example of a solid is the sphere.
Now we want to have a sphere in our world.
scene HelloWorld2;
Scene {
PerspectiveCamera {
location := <0, 0, -5>;
}
World {
Sphere {
}
}
}
|
Example 2: HelloWorld2
and how it looks like |
We just added a new object of the sphere to the world.
This was done by writing the Class name (Sphere) followed
by an empty block inside the World's block.
If you try to render this, the image would be black, as there is no
light source defined. If we add a pointlight we get our first image.
scene HelloWorld;
Scene {
PerspectiveCamera {
location := <0, 0, -5>;
}
World {
PointLight {
location := <-10, 10, -10>;
}
Sphere {
SimpleTexture{} // to be removed
}
}
}
|
Example 3: HelloWorld
and how it looks like |
The light source is located 10 units left, 10 units above and
10 units behind the origin.
Applying Values To Properties
Every Object may have properties. Applying new values to properties
changes the object's attributes.
If we want a smaller sphere, we can apply a different radius to it.
scene HelloWorld;
Scene {
PerspectiveCamera {
location := <0, 0, -5>; // to be removed
look_at := <0, 0, 0>; // to be removed
}
World {
PointLight {
location := <-10, 10, -10>; // to be removed
}
Sphere {
radius := 0.5;
SimpleTexture{} // to be removed
}
}
}
|
Example 4: HelloWorldSmall
and how it looks like |
The properties have a predefined value.
See the Object Reference for details.
Using Object References
Sometimes it is usefull to have a reference to a object. It is
possible to share this object through a reference.
In the following example we declare a object reference with the
keyword "var", the reference name (myLight) and the type of the
reference (PointLight).
We can assign this reference to a property, which is of the same type
or one of the base classes.
if we want to modify properties of the referred object, we can
use the dot-operator. In the example below, the light source was
initially on the left side. But later on it was overwritten by using the
dot-operator. The light source is now on the right side.
scene HelloWorld;
Scene {
PerspectiveCamera {
location := <0, 0, -5>; // to be removed
look_at := <0, 0, 0>; // to be removed
}
World {
var myLight : PointLight;
myLight := PointLight {
location := <-10, 10, -10>;
}
_lights := myLight;
myLight.location := <10, 10, -10>;
Sphere {
SimpleTexture{} // to be removed
}
}
}
|
Example 5: RefDemo
and how it looks like |
Adding more Objects
If we want to have more than one sphere in our world, no problem:
just add them to the world's block.
As we don't want to have them on the same position we apply different
centers to them:
scene HelloWorld;
Scene {
PerspectiveCamera {
location := <0, 0, -5>;
look_at := <0, 0, 0>;
}
World {
PointLight {
location := <-10, 10, -10>;
}
Sphere {
center := <-1, -1, 0>;
radius := 0.5;
}
Sphere {
center := <1, -1, 0>;
radius := 0.5;
}
Sphere {
center := <-1, 1, 0>;
radius := 0.5;
}
Sphere {
center := <1, 1, 0>;
radius := 0.5;
}
}
}
|
Example 6: HelloWorldQuad
and how it looks like |
This gives four spheres.
Textures
If we want to change the object's appearance, we have to add a texture
object to its block. The texture object may contain one Pigment and one
Finish Object.
Simple Pigment
The pigment describes the color of the object. The simpliest pigment
object is the SolidColorPigment. It has only a color property. The
hole object is tinted with this color.
scene HelloWorld;
Scene {
PerspectiveCamera {
location := <0, 0, -5>;
look_at := <0, 0, 0>;
}
World {
PointLight {
location := <-10, 10, -10>;
}
Sphere {
SimpleTexture {
SolidColorPigment {
color := rgb <0.7, 0.7, 1>;
}
}
}
}
}
|
Example 7: BlueSphere
and how it looks like |
Algorithmic Pigments
As uni-colored objects are a little bit boaring, we want to have
objects made from wood, stone. This is what the XYZPigment is for.
We can define a Pattern that describes how the colors are distributed
and to which colors the pattern maches to. This is done by including
a Pattern and a Colormap object to the XYZPigment.
The following example uses the CheckerPattern to define the tiles and
a SimpleColorMap where we can define two colors. The result is a
black and white tiled floor.
Note: we have to lower the floor a little bit in order to cut the
pattern not at its border (which would look not as expected).
scene TiledFloor;
Scene {
PerspectiveCamera {
location := <0, 2, -10>;
look_at := <0, 0, 0>;
angle := 45;
}
World {
PointLight {
location := <0, 5, 0>;
fade_power := 2;
fade_distance := 7;
}
Plane {
normal := <0, 1, 0>;
distance := -0.001;
SimpleTexture {
XYZPigment {
CheckerPattern {
size := 2;
}
SimpleColorMap {
color1 := rgb <1, 1, 1>;
color2 := rgb <0.15, 0.15, 0.15>;
}
}
}
}
}
}
|
Example 8: TiledFloor
and how it looks like |
scene Wood;
Scene {
PerspectiveCamera {
location := <0, 3, -5>;
look_at := <0,0.5,2>;
}
World {
PointLight {
location := <-5, 5, -5>;
}
Box {
point1 := <-2,-0.5,0>;
point2 := <2,0.5,15>;
SimpleTexture {
XYZPigment {
WoodPattern {
noise := 0.2;
turbulence := 0;
octaves := 1;
xturbulence := 0;
yturbulence := 0;
zperturbation := 0.9;
zfrequency := 2;
zoffset := 0;
znoise := 0.7;
Scale {
scale := <0.2,0.2,4>;
}
}
ColorMapList {
ColorMapListEntry { value := 0; color := rgb <0.7, 0.5, 0>; }
ColorMapListEntry { value := 0.2; color := rgb <0.5, 0.3, 0>; }
ColorMapListEntry { value := 0.8; color := rgb <0.7, 0.5, 0>; }
ColorMapListEntry { value := 1; color := rgb <0.7, 0.5, 0>; }
}
}
Finish {
ambient := 0.2;
diffuse := 0.9;
}
}
}
}
}
|
Example 9: Wood
and how it looks like |
Finish
Additional to the pigment of an object we can adjust the material.
This is done with the Finish object.
Smooth polished objects reflect light in the same angle it came in.
The Reflection property adjusts the amount of reflected rays. If set to 1,
light is totally reflected at the surface.
The color of the reflected light is usually filtered by metallic objects.
To simulate this, we can set the value of the property metallic to 1. The
mirrored floor in the example below gets filtered red at the right sphere.
scene MirrorSphere;
Scene {
PerspectiveCamera {
location := <0, 3, -5>;
look_at := <0, 1, 0>;
angle := 45;
}
World {
var metalFinish :Finish;
var plasticFinish :Finish;
var c2: Color;
c2 := rgb <1, 0.7, 0.7>;
metalFinish := Finish {
reflection := 0.75;
metallic := 1;
}
plasticFinish := Finish {
reflection := 0.75;
metallic := 0;
}
PointLight {
location := <0, 5, 0>;
fade_power := 2;
fade_distance := 7;
}
Sphere {
center := <-1, 1, 0>;
SimpleTexture {
SolidColorPigment {
color := c2;
}
finish := plasticFinish;
}
}
Sphere {
center := <1, 1, 0>;
SimpleTexture {
SolidColorPigment {
color := c2;
}
finish := metalFinish;
}
}
Plane {
normal := <0, 1, 0>;
distance := -0.001;
SimpleTexture {
XYZPigment {
CheckerPattern {
size := 2;
}
SimpleColorMap {
color1 := rgb <1, 1, 1>;
color2 := rgb <0.15, 0.15, 0.15>;
}
}
}
}
}
}
|
Example 10: MirrorSphere
and how it looks like |
If we want to have a translucent object, we have to adjust the properties
refraction and ior (index of refraction).
Ior controls how much the light is bent when it travels through the object's
surface. Some examples:
diamond 2.42,
glass 1.45,
water 1.33,
ice 1.31,
air 1.00
scene GlassSphere;
Scene {
PerspectiveCamera {
location := <0, 3, -5>;
look_at := <0, 1, 0>;
angle := 45;
}
World {
var glassFinish :Finish;
var c2: Color;
c2 := rgbt <1, 1, 1, 0.95>;
glassFinish := Finish {
refraction := 1.0;
ior := 1.5;
}
PointLight {
location := <0, 5, 0>;
fade_power := 2;
fade_distance := 7;
}
Sphere {
center := <0, 1, 0>;
SimpleTexture {
SolidColorPigment {
color := c2;
}
finish := glassFinish;
}
}
Plane {
normal := <0, 1, 0>;
distance := -0.001;
SimpleTexture {
XYZPigment {
CheckerPattern {
size := 2;
}
SimpleColorMap {
color1 := rgb <1, 1, 1>;
color2 := rgb <0.15, 0.15, 0.15>;
}
}
}
}
}
}
|
Example 11: GlassSphere
and how it looks like |
Loop- and Conditional-Statements
A very strong feature of CoolRay is the possibility to
use loops and conditional statements. It is possible to create
several objects with a loops.
The For Loop
Constructive Solid Geometric (CSG)
CSG is used to create complex objects out if simple basic objects.
Union
scene CSGUnion;
Scene {
PerspectiveCamera {
location := <1, 3, -5>;
angle := 45;
}
World {
var glassFinish :Finish;
var c1: Color;
var c2: Color;
background_color := rgb <1, 1, 1>;
c1 := rgbt <1, 0.5, 0.5, 0.5>;
c2 := rgbt <0.5, 0.5, 1, 0.5>;
PointLight {
location := <0, 5, 0>;
fade_power := 2;
fade_distance := 7;
}
Union {
Sphere {
center := <-0.5, -0, 0>;
SimpleTexture {
SolidColorPigment {
color := c1;
}
}
}
Sphere {
center := <0.5, 0, 0>;
SimpleTexture {
SolidColorPigment {
color := c2;
}
}
}
}
}
}
|
Example 12: CSGUnion
and how it looks like |
Merge
scene CSGMerge;
Scene {
PerspectiveCamera {
location := <1, 3, -5>;
angle := 45;
}
World {
var glassFinish :Finish;
var c1: Color;
var c2: Color;
background_color := rgb <1, 1, 1>;
c1 := rgbt <1, 0.5, 0.5, 0.5>;
c2 := rgbt <0.5, 0.5, 1, 0.5>;
PointLight {
location := <0, 5, 0>;
fade_power := 2;
fade_distance := 7;
}
Merge {
Sphere {
center := <-0.5, -0, 0>;
SimpleTexture {
SolidColorPigment {
color := c1;
}
}
}
Sphere {
center := <0.5, 0, 0>;
SimpleTexture {
SolidColorPigment {
color := c2;
}
}
}
}
}
}
|
Example 13: CSGMerge
and how it looks like |
Difference
scene CSGDifference;
Scene {
PerspectiveCamera {
location := <1, 3, -5>;
angle := 45;
}
World {
var glassFinish :Finish;
var c1: Color;
var c2: Color;
background_color := rgb <1, 1, 1>;
c1 := rgbt <1, 0.5, 0.5, 0.5>;
c2 := rgbt <0.5, 0.5, 1, 0.5>;
PointLight {
location := <0, 5, 0>;
fade_power := 2;
fade_distance := 7;
}
Difference {
Sphere {
center := <-0.5, -0, 0>;
SimpleTexture {
SolidColorPigment {
color := c1;
}
}
}
Sphere {
center := <0.5, 0, 0>;
SimpleTexture {
SolidColorPigment {
color := c2;
}
}
}
}
}
}
|
Example 14: CSGDifference
and how it looks like |
Intersection
scene CSGIntersect;
Scene {
PerspectiveCamera {
location := <1, 3, -5>;
angle := 45;
}
World {
var glassFinish :Finish;
var c1: Color;
var c2: Color;
background_color := rgb <1, 1, 1>;
c1 := rgbt <1, 0.5, 0.5, 0.5>;
c2 := rgbt <0.5, 0.5, 1, 0.5>;
PointLight {
location := <0, 5, 0>;
fade_power := 2;
fade_distance := 7;
}
Intersect {
Sphere {
center := <-0.5, -0, 0>;
SimpleTexture {
SolidColorPigment {
color := c1;
}
}
}
Sphere {
center := <0.5, 0, 0>;
SimpleTexture {
SolidColorPigment {
color := c2;
}
}
}
}
}
}
|
Example 15: CSGIntersect
and how it looks like |
|