|
POV-Ray - Goban
last edited: 15/5/11
 Scene render time: 1d, 1h, 1m, 28s
As a fellow go player, this had to be my second project. For the stones, I use a nice bezier spline points come from here. I tried to replicate high-quality goban and stones, so the lines and hoshi are carved, and the stones somewhat fat and meaty. I am trying to figure out how to blur the reflection, as you'll never get such a clear reflection even on a high-end goban.
Update 10/5/2011 : I wrote a little python script (download) which will parse the ascii output of gnugo (cheap method for reading an .sgf file without any library) and generate a POV-Ray source file of your games, at any position. Just extract the two files, and run the following command in a command prompt (you will need python on your machine):
python seichi.py "C:\path\to\your\game.py" 42 |
You can also omit the position (42), it will then generate a source for the last position in the game. The script (should) also works as is on linux.
Update 11/5/2011: I finished coding tatami for the floor! Here's a render which took one hour, the game is famous one between Honibō Shūsaku and Gennan Inseki (stone positions generated from a .sgf file by the python script):

And here are a few renders of random stones, followed by the (uncommented and ugly) source file.



Source code (file available here)
global_settings{ assumed_gamma 1.0 }
#declare enable_dof = 1;
#include "textures.inc"
#include "woods.inc"
#include "functions.inc"
#include "shapes.inc"
// radiosity (global illumination) settings
global_settings {
radiosity {
pretrace_start 0.08 // start pretrace at this size
pretrace_end 0.04 // end pretrace at this size
count 30 // higher -> higher quality (1..1600) [35]
nearest_count 5 // higher -> higher quality (1..10) [5]
error_bound 1.8 // higher -> smoother, less accurate [1.8]
recursion_limit 10 // how much interreflections are calculated (1..5+) [3]
low_error_factor .5 // reduce error_bound during last pretrace step
gray_threshold 0.0 // increase for weakening colors (0..1) [0]
minimum_reuse 0.015 // reuse of old radiosity samples [0.015]
brightness 1 // brightness of radiosity effects (0..1) [1]
adc_bailout 0.01/2
//normal on // take surface normals into account [off]
//media on // take media into account [off]
//save_file "file_name" // save radiosity data
//load_file "file_name" // load saved radiosity data
//always_sample off // turn sampling in final trace off [on]
//max_sample 1.0 // maximum brightness of samples
}
}
#declare Camera_0 =
camera
{
perspective angle 15
location <2.0 , 6.0 ,-15.0>
right x*image_width/image_height
look_at <0.0 , 5.0 , 0.0>
#if (enable_dof = 1)
focal_point <-1, 2.5, -1> blur_samples 40 aperture 0.2
#end
}
#declare look_x = -6;
#declare look_y = 4;
#declare Camera_1 =
camera
{
angle 70
location <2.0+look_x , 8 ,-3.0+look_y>
right x*image_width/image_height
look_at <-2.0+look_x , 2.5 , 3.2+look_y>
#if (enable_dof = 1)
focal_point <-5, 5.2, -5> blur_samples 80 aperture 0.4
#end
}
#declare Camera_2 =
camera
{
angle 38
location <20.0 , 33.0, 30.0>
right x*image_width/image_height
look_at <1.5 , 4.0 , 3.0>
#if (enable_dof = 1)
focal_point <1, 5.5, 1> blur_samples 100 aperture 2.5
#end
}
#declare Camera_3 =
camera
{
angle 90
location <0.0 , 3.0 ,-0.001>
right x*image_width/image_height
look_at <0.0 , 1.0 , 0.0>
}
#declare Camera_4 =
camera
{
perspective angle 58
location <0.0 , 25.0 ,-14>
right x*image_width/image_height
look_at <0.0 , 3.0 , -1.0>
#if (enable_dof = 1)
focal_point <0, 5.2, 0> blur_samples 60 aperture 0.5
#end
}
camera{Camera_4}
// create a point "spotlight" (conical directed) light source
light_source {
<0,0,0> // light's position (translated below)
color rgb 0.3 // light's color
spotlight // this kind of light source
translate <3000, 3000, -3000> // position of light
point_at <-5, 0, 5> // direction of spotlight
radius 0.01 // hotspot (inner, in degrees)
tightness 50 // tightness of falloff (1...100) lower is softer, higher is tighter
falloff 0.2 // intensity falloff radius (outer, in degrees)
}
// create a point "spotlight" (conical directed) light source
light_source {
<0,0,0> // light's position (translated below)
color rgb 0.6 // light's color
spotlight // this kind of light source
translate <1000, 3000, -0> // position of light
point_at <0, 0, 0> // direction of spotlight
radius 0.4 // hotspot (inner, in degrees)
tightness 50 // tightness of falloff (1...100) lower is softer, higher is tighter
falloff 0.5 // intensity falloff radius (outer, in degrees)
}
light_source{< 3000,3000,-3000> color rgb 0.6 }
light_source{< 7,8,7> color rgb 0.8}
#declare kaya =
texture {
pigment {
wood
turbulence 0.03
omega 0.65725
lambda 0.425
color_map {
[0.250 color rgbt <1.00000, 0.53373, 0.11665, 0.000>]
[0.350 color rgbt <0.66275, 0.28607, 0.00000, 0.000>]
[0.525 color rgbt <1.00000, 0.53363, 0.11715, 0.000>]
[0.600 color rgbt <0.66475, 0.28647, 0.00000, 0.000>]
[0.750 color rgbt <1.00000, 0.53353, 0.11565, 0.000>]
[0.850 color rgbt <0.66275, 0.28667, 0.00000, 0.000>]
[1.000 color rgbt <1.00000, 0.53143, 0.11795, 0.000>]
}
scale <0.25, 0.225, 1.0>
}
}
texture {
pigment {
wood
scale 1.01275
turbulence 0.0435
omega 0.65
lambda 3.15
color_map {
[0.200 color rgbt <0.56695, 0.17347, 0.00000, 0.8250>]
[0.350 color rgbt <0.96471, 0.54510, 0.22753, 0.7710>]
[0.400 color rgbt <0.56341, 0.17547, 0.00000, 0.9150>]
[0.615 color rgbt <0.96472, 0.54510, 0.22553, 0.7590>]
[0.700 color rgbt <0.56671, 0.17687, 0.00000, 0.7920>]
[0.850 color rgbt <0.96485, 0.54510, 0.22453, 0.8975>]
[1.000 color rgbt <0.56478, 0.17247, 0.00000, 0.9750>]
}
scale <0.225, 0.2725, 1.0>
translate <-0.35, 0.095, 1.25>
}
}
difference
{
union
{
box
{
<0,1.999,0>, <19,2,19>
texture { kaya translate <0,3,0>}
finish
{
diffuse 1.0
ambient 0.0
specular 0.0
phong 0.05
reflection { 0.3 }
//conserve_energy
}
translate <-19/2,0,-19/2>
}
box
{
<0,-1,0>, <19,1.999,19>
texture { kaya translate <0,3,0>}
finish
{
diffuse 1.0
ambient 0.0
specular 0.0
phong 0.05
reflection { 0 }
//conserve_energy
}
translate <-19/2,0,-19/2>
}
}
union
{
#declare i = 0;
#while (i < 19)
cylinder { <0,2.025,i>, <18,2.025,i>, 0.035 }
cylinder { , , 0.035 }
#declare i = i + 1;
#end
sphere { <3,2.24,3>, 0.25 }
sphere { <3,2.24,9>, 0.25 }
sphere { <3,2.24,15>, 0.25 }
sphere { <9,2.24,3>, 0.25 }
sphere { <9,2.24,9>, 0.25 }
sphere { <9,2.24,15>, 0.25 }
sphere { <15,2.24,3>, 0.25 }
sphere { <15,2.24,9>, 0.25 }
sphere { <15,2.24,15>, 0.25 }
pigment { rgb <0.001,0.001,0.001> }
finish
{
diffuse 1.0
ambient 0.5
specular 0.1
phong 1
reflection { 0.1 metallic }
conserve_energy
}
translate <-18/2, 0, -18/2>
}
translate <0,3,0>
}
union
{
sphere { <-7,0.5,-7>, 1.5 }
sphere { <7,0.5,7>, 1.5 }
sphere { <-7,0.5,7>, 1.5 }
sphere { <7,0.5,-7>, 1.5 }
texture { kaya }
finish
{
diffuse 1.0
ambient 0.0
specular 0.0
phong 0.05
reflection { 0.3 }
//conserve_energy
}
}
#declare straw=
texture{
//pigment { bozo color_map { [0.2 color rgb <0.65,0.50,0.25>] [0.5 color rgb <116/255,97/255,46/255>] [0.8 color rgb <179/255,133/255,23/255>] } scale <10,0.1,1> }
pigment { bozo color_map { [0.2 color rgb <80/255,59/255,18/255>] [0.5 color rgb <58/255,43/255,21/255>] [0.8 color rgb <78/255,48/255,10/255>] } scale <100,0.1,10> rotate y*4 }
normal { bumps 0.25 scale 0.015}
finish { ambient 1 diffuse 1 specular 0.05 phong 0.2 }
}
#declare mg=0.3;
#declare mat_x = 0.10; // distance between neighboring threads in the x direction
#declare mat_z = 1.00; // distance between neighboring threads in the z direction
#declare mat_t = 0.18; // relative thickness in the x and z directions
#declare mat_w = 0.04; // amplitude of the weaving effect
#declare mat_y = 0.06; // relative thickness in the y direction
#declare mat_s = 0.7*2; // spacing between mats (doubled)
// From http://hea-www.harvard.edu/~fine/POV/src/fabric.pov
#declare H_streaks = pigment { bozo color_map { [0.2 color rgb <0.1,0.0,0.5>] [0.8 color rgb <0.2,0.25,0.4>] } scale <10,0.1,1> }
#declare V_streaks = pigment { bozo color_map { [0.2 color rgb <0.1,0.0,0.5>] [0.8 color rgb <0.2,0.25,0.4>] } scale <0.1,10,1> }
#declare fabric = texture {
pigment { checker pigment { H_streaks } pigment { V_streaks } scale 0.5*0.17 }
normal { bump_map { gif "fabric.gif" bump_size 10 } scale 0.17 }
finish { ambient 0.05 diffuse 0.02 specular 0.1 }
}
isosurface
{
function { f_mesh1( x,y,z, mat_x, mat_z, mat_t, mat_w, mat_y) }
contained_by { box{ <-6 + mat_s,-0.2, 6 + mat_s>, < 60,0.2, 60> } }
threshold 0.01
max_gradient mg
texture { straw }
translate <0,-1,0>
}
isosurface
{
function { f_mesh1( x,y,z, mat_x, mat_z, mat_t, mat_w, mat_y) }
contained_by { box{ < 6 - mat_s,-0.2,-6 - mat_s>, <-60,0.2,-60> } }
threshold 0.01
max_gradient mg
texture { straw }
translate <0,-1,0>
}
isosurface
{
function { f_mesh1( x,y,z, mat_z, mat_x, mat_t, mat_w, mat_y) }
contained_by { box{ <-6 - mat_s,-0.2,-6 + mat_s>, <-60,0.2, 60> } }
threshold 0.01
max_gradient mg
texture { straw rotate y*90 }
translate <0,-1,0>
}
isosurface
{
function { f_mesh1( x,y,z, mat_z, mat_x, mat_t, mat_w, mat_y) }
contained_by { box{ < 6 + mat_s,-0.2, 6 - mat_s>, < 60,0.2,-60> } }
threshold 0.01
max_gradient mg
texture { straw rotate y*90 }
translate <0,-1,0>
}
union
{
Round_Box(<-6 + mat_s, -0.42, -6 + (mat_s/2)>, < -6, 0.2, 60>, 0.3, off)
Round_Box(<-6, -0.42, -6 + (mat_s/2)>, < -6-mat_s, 0.2, 60>, 0.3, off)
Round_Box(< 6 + mat_s, -0.42, 6 + (mat_s/2)>, < 6 , 0.2, -60>, 0.3, off)
Round_Box(< 6, -0.42, 6 + (mat_s/2)>, < 6 -mat_s, 0.2, -60>, 0.3, off)
texture { fabric rotate y*90 }
translate <0,-1.1,0>
}
union
{
Round_Box(<-6 - (mat_s/2), -0.42, 6 + mat_s>, <60, 0.2, 6 >, 0.3, off)
Round_Box(<-6 - (mat_s/2), -0.42, 6 >, <60, 0.2, 6 - mat_s >, 0.3, off)
Round_Box(<6 + mat_s, -0.42, -6 + mat_s>, <-60, 0.2, -6>, 0.3, off)
Round_Box(<6 + mat_s, -0.42, -6 >, <-60, 0.2, -6 - mat_s>, 0.3, off)
texture { fabric }
translate <0,-1.1,0>
}
#declare stone_rad = 0.49;
#declare stone_hgt = 0.45;
#declare stone_top_roundnes = .4;
#declare stone_edge_roundnes = .35;
#declare stone =
lathe
{
bezier_spline 8
<0,stone_hgt/2>
<0,-stone_hgt/2>
translate y*stone_hgt/2
}
#declare white_stone =
texture { T_Wood7 rotate z*30 scale 0.2 }
texture
{
pigment { rgbf <0.63,0.68,0.7,0.8> }
finish
{
diffuse .6
ambient 0.1
specular 0.1
phong 0.4
reflection { 0.2 metallic }
conserve_energy
}
}
#declare black_stone =
texture
{
pigment { rgb <0.001,0.001,0.001> }
finish
{
diffuse .4
ambient 0.1
specular 0.01
phong 0.05
phong_size 10
reflection { 0.05 metallic }
conserve_energy
}
}
object
{
union
{
object { stone translate <-7,2,-6> texture { white_stone }}
object { stone translate <-7,2,-4> texture { white_stone }}
object { stone translate <-6,2,-7> texture { white_stone }}
object { stone translate <-6,2,6> texture { black_stone }}
object { stone translate <-5,2,-7> texture { white_stone }}
object { stone translate <-5,2,-6> texture { black_stone }}
object { stone translate <-4,2,-7> texture { black_stone }}
object { stone translate <-4,2,-6> texture { black_stone }}
object { stone translate <0,2,-7> texture { black_stone }}
object { stone translate <2,2,-6> texture { black_stone }}
object { stone translate <4,2,-7> texture { black_stone }}
object { stone translate <4,2,6> texture { black_stone }}
object { stone translate <6,2,-8> texture { black_stone }}
object { stone translate <6,2,-6> texture { white_stone }}
object { stone translate <6,2,-4> texture { white_stone }}
object { stone translate <6,2,0> texture { white_stone }}
object { stone translate <6,2,6> texture { black_stone }}
object { stone translate <7,2,-7> texture { white_stone }}
object { stone translate <7,2,4> texture { white_stone }}
}
rotate y*-270
translate <0,3,0>
}
|
|
|
|
Adrian Petrescu
This is absolutely gorgeous. I'm trying to replicate that first image at the top; by any chance is the tatami file available somewhere as well?
I'd love to basically render every move of a game in the style of your first image, and then blur-transition them together to make a screensaver.
#2 – 21 November, 2012 at 8:07 am
Bill B.
This is awesome, really well done. Thank you for including the link to Harvard's gifs in the .pov, that really helped get it rendering.
I especially like the seichi.py utility, that's really neat. I have two questions/comments about seichi.py, bearing in mind that I've not studied either the Python script nor the goban.pov file in detail at this point.
The first: what's in the zipped up portion of seichi.py? I'm guessing it's just the compressed version of the POV-Ray stuff above the stone code in the goban .pov file that gets created?
The next is just feedback that might be of interest: Provided I change the " 19" around line 72 to read " 9" it also generates stone positions for .sgf files from 9x9 boards, though they're kind of interesting. The main part gets put in correctly apparently using the lower right corner of the goban as the location for the 9x9 play. So the layout is good as far as the stones go, but hilariously off for who owns all that space beyond.
Thanks for making both seichi.py and goban.pov available. I appreciate that sharing.
#1 – 21 September, 2011 at 11:13 pm