func hexToColorNRGBA(hex string) color.NRGBA { c := color.NRGBA{} getIntensity := func(str string) uint8 { if u, err := hexToUint8(str); err == nil { return u } return 0 } if len(hex) >= 6 { c.R = getIntensity(hex[0:2]) c.G = getIntensity(hex[2:4]) c.B = getIntensity(hex[4:6]) } if len(hex) == 8 { c.A = getIntensity(hex[6:8]) } else { c.A = 255 } return c }
func writeImagePng(filename string, pixels []float32, xres, yres int) { outImage := image.NewNRGBA(image.Rect(0, 0, xres, yres)) to_byte := func(v float32) uint8 { // apply gamma and convert to 0..255 return uint8(Clamp(255.0*math.Pow(float64(v), 1.0/2.2), 0.0, 255.0)) } for y := 0; y < yres; y++ { for x := 0; x < xres; x++ { var fcolor color.NRGBA fcolor.R = to_byte(pixels[3*(y*xres+x)+0]) fcolor.G = to_byte(pixels[3*(y*xres+x)+1]) fcolor.B = to_byte(pixels[3*(y*xres+x)+2]) fcolor.A = 0xff outImage.Set(x, y, fcolor) } } f, err := os.Create(filename) defer f.Close() if err != nil { Error("Error writing PNG \"%s\"", filename) } else { png.Encode(f, outImage) } }
// render one row of pixels by calculating a colour for each pixel. // The image pixel row number is r. Fill the pixel colour into the // image after the colour has been calculated. func (r row) render(rt *rtrace, a, b, c lin.V3, img *image.NRGBA, seed *uint32) { rgba := color.NRGBA{0, 0, 0, 255} t, v1, v2 := lin.NewV3(), lin.NewV3(), lin.NewV3() // temp vectors. colour, orig, dir := lin.NewV3(), lin.NewV3(), lin.NewV3() for x := (rt.iw - 1); x >= 0; x-- { colour.SetS(13, 13, 13) // Use a very dark default colour. // Cast 64 rays per pixel for blur (stochastic sampling) and soft-shadows. for cnt := 0; cnt < 64; cnt++ { // Add randomness to the camera origin 17,16,8 t.Scale(&a, rnd(seed)-0.5).Scale(t, 99).Add(t, v1.Scale(&b, rnd(seed)-0.5).Scale(v1, 99)) orig.SetS(17, 16, 8).Add(orig, t) // Add randomness to the camera direction. rnda := rnd(seed) + float64(x) rndb := float64(r) + rnd(seed) dir.Scale(t, -1) dir.Add(dir, v1.Scale(&a, rnda).Add(v1, v2.Scale(&b, rndb)).Add(v1, &c).Scale(v1, 16)) dir.Unit() // accumulate the colour from each of the 64 rays. sample := rt.sample(*orig, *dir, seed) colour = sample.Scale(&sample, 3.5).Add(&sample, colour) } // set the final pixel colour in the image. rgba.R = byte(colour.X) // red rgba.G = byte(colour.Y) // green rgba.B = byte(colour.Z) // blue img.SetNRGBA(rt.iw-x, int(r), rgba) } }
func setRandomBrightness(c *color.NRGBA, max uint8) { minc := min3(c.R, c.G, c.B) maxc := max3(c.R, c.G, c.B) if maxc > max { return } n := rand.Intn(int(max-maxc)) - int(minc) c.R = uint8(int(c.R) + n) c.G = uint8(int(c.G) + n) c.B = uint8(int(c.B) + n) }