SunBurn : DSL
Tags: SunBurn, Raytracing, DSL, Scala June 19, 2009

J’ai commencé à créer un début de DSL (Domain Specific Language) pour SunBurn. Scala permet en effet de créer des structures qui ressemblent à d’autres langages alors qu’il s’agit de Scala normal. J’ai donc essayé de me rapprocher d’un langage de type POV-ray. Lorsque la version 2.8 de Scala sera sortie, il sera peut-être possible de l’améliorer avec des paramètres nommés et des valeurs par défaut. Enfin on n’en est pas encore là !

Voici une capture d’écran d’un rendu suivi du code qui a permis de le créer :

import sunburn.geometry._
import sunburn.geometry.Vector3D._
import sunburn.core._
import sunburn.samplers._
import sunburn.colors._
import sunburn.colors.RGBColor._
import sunburn.materials._
import sunburn.cameras._
import sunburn.lights._

object Main {
   def main(args: Array[String]) = {     
      val myworld = new World {
         objects (
            new Sphere {
               center = (0.0, 12.0, 0.0)                
               radius = 10.0                
               material = new MatteMaterial {                    
                  color = Yellow                    
                  diffuse = 0.5                    
                  ambient = 0.5                
               }            
            },            
            new Sphere {                
               center = (20.0, 10.0, 0.0)                
               radius = 5.0                
               material = new MatteMaterial {                    
                  color = Red                    
                  diffuse = 1                    
                  ambient = 1                
               }            
            },            
            new Plane {                
               point = (0,0,0)                
               normal = (0.0, 1.0, 0)                
               material = new MatteMaterial {                    
                  color = RGBColor(0.2,0.2,0.2)                    
                  diffuse = 2.2                    
                  ambient = 2.2                
               }            
            }        
         )            
         
         backgroundColor = Green                
         ambientLight = new SimpleAmbientLight {            
            intensity = 0.2            
            color = Blue        
         }        
         
         lights (            
            new PointLight {                
               intensity = 8.0                
               color = White                
               location =  (10,30,10)            
            }        
         )     
      }        
      
      val vp = new ViewPlane {        
         size = (800,600)        
         resolution = 0.2        
         sampler = new BufferedSampler( new ShuffledSampler(
                     new MultiJitteredSampler(100)))    
      }    
      
      val c = new ThinLensCamera(myworld, vp) {        
         eye =  Point3D(0,40,40)        
         lookat = Point3D(0,0,0)        
         viewDistance = 50.0        
         focalDistance = 40.0        
         lensRadius = 2.0    
      }        
      
      val r = new Displayer(c)    
      
      c.render  
   }
}

Le code est assez explicite. Au début on a les différents “imports”. Ensuite on a la définition du monde (“World”) avec les objets qui le composent, les lumières (dont la lumière ambiente) ainsi que la couleur à l’infini.

On crée ensuite un ViewPlane. Le ViewPlane définit :

  • la taille de l’image finale (ici 800x600 pixels).
  • la résolution, c’est-à-dire la taille d’un pixel de l’image finale en unité du monde. Ici avec une résolution de 0.2, 1 unité dans le monde occupe 5 pixels (5 * 0.2)
  • l’échantillonneur (sampler). Pour chaque pixel de l’image finale, on envoie plusieurs rayons répartis sur le carré de taille 0.2x0.2. La répartition de ces rayons dépend de l’échantillonneur. Ici on a 100 rayons par pixel avec une répartition MultiJittered. On fait ensuite la moyenne des différentes couleurs renvoyées par les rayons.

Ensuite on définit une caméra utilisant une lentille mince (ThinLens) que l’on règle pour que la distance focale soit sur la sphère jaune.

Enfin on crée un Displayer sur cette caméra. Il s’agit en fait d’une fenêtre affichant l’image au fur et à mesure que le rendu s’effectue (ainsi que l’image finale bien sûr). On lance ensuite le rendu de la caméra avec la méthode “render”.

Vous pouvez trouver le code (sous Licence GPL v3) ici