Guest User

Untitled

a guest
Mar 18th, 2018
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.27 KB | None | 0 0
  1. import java.awt.Color
  2. import java.awt.image.BufferedImage
  3. import java.io.File
  4. import javax.imageio.ImageIO
  5.  
  6. object RayTracing extends App {
  7.  
  8. private def sq(x: Double): Double = x * x
  9.  
  10. case class Point(x: Double, y: Double, z: Double) {
  11. def +(v: Vector): Point = Point(x + v.x, y + v.y, z + v.z)
  12. def distanceSq(p: Point): Double = sq(x - p.x) + sq(y - p.y) + sq(z - p.z)
  13. def distance(p: Point): Double = Math.sqrt(distanceSq(p))
  14. }
  15.  
  16. case class Vector(x: Double, y: Double, z: Double) {
  17. def +(v: Vector): Vector = Vector(x + v.x, y + v.y, z + v.z)
  18. def *(d: Double): Vector = Vector(x * d, y * d, z * d)
  19. def /(d: Double): Vector = Vector(x / d, y / d, z / d)
  20. def dot(v: Vector): Double = x * v.x + y * v.y + z * v.z
  21. def opposite: Vector = Vector(-x, -y, -z)
  22. def isZero: Boolean = x == 0.0 && y == 0.0 && z == 0.0
  23. def normalize: Vector = if (!isZero) this / length else this
  24. def lengthSq: Double = sq(x) + sq(y) + sq(z)
  25. def length: Double = Math.sqrt(lengthSq)
  26. }
  27.  
  28. object Vector {
  29. def apply(to: Point, from: Point): Vector = Vector(to.x - from.x, to.y - from.y, to.z - from.z)
  30. }
  31.  
  32. case class Sphere(center: Point, radius: Double) {
  33. assert(radius > 0.0)
  34. lazy val radiusSq: Double = sq(radius)
  35. }
  36.  
  37. def rayTracing(width: Int, height: Int, widthSize: Double, focal: Point, screenToFocal: Vector): Unit = {
  38. assert(width > 0 && height > 0)
  39. assert(!screenToFocal.isZero)
  40.  
  41. val rayStep = 1.0
  42. val rayIterations = 10000
  43.  
  44. val halfWidth = (width - 1) / 2.0
  45. val halfWidthSize = (widthSize - 1) / 2.0
  46. val horizontalVectorTemplate = Vector(screenToFocal.y, -screenToFocal.x, 0.0).normalize
  47. val halfHeight = (height - 1) / 2.0
  48. val halfHeightSize = (height * widthSize / width - 1) / 2.0
  49.  
  50. val spheres = List(Sphere(Point(500, 1000, 200), 200), Sphere(Point(1000, 700, 300), 200))
  51.  
  52. val image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
  53. val g = image.createGraphics()
  54.  
  55. for {
  56. y <- (0 until height).par
  57. x <- 0 until width
  58. } {
  59. val horizontalVector = horizontalVectorTemplate * halfWidthSize * (x - halfWidth) / halfWidth
  60.  
  61. val verticalVector = Vector(0.0, 0.0, halfHeightSize * ((height - y - 1) - halfHeight) / halfHeight) // Assume screenToFocal.z == 0.0 | FIXME
  62. val vectorPointOnScreen = screenToFocal + horizontalVector + verticalVector
  63.  
  64. val initialPosition = focal + vectorPointOnScreen
  65. val initialVector = vectorPointOnScreen.normalize * rayStep
  66.  
  67. var position = initialPosition
  68. var vector = initialVector
  69. var stopped = false
  70. var i = 0
  71. var darkness = 0.0
  72. var color: Option[Color] = None
  73. while (!stopped && i < rayIterations) {
  74. position += vector
  75.  
  76. // -- Begin collision detection
  77.  
  78. if (position.z < 0.0) { // Ground
  79. stopped = true
  80.  
  81. val squareSpacing = 100
  82. val square = (Math.floor(position.x / squareSpacing) + Math.floor(position.y / squareSpacing)) % 2 == 0
  83.  
  84. color = Some(if (square) Color.BLACK else Color.WHITE)
  85. } else { // Spheres
  86. for (sphere <- spheres) {
  87. if (position.distanceSq(sphere.center) <= sphere.radiusSq) {
  88. val normal = Vector(position, sphere.center).normalize
  89. vector = vector + normal.opposite * 2 * vector.dot(normal)
  90. darkness += (if (position.z - sphere.center.z >= 0) 0.95 * (1 - normal.dot(Vector(0, 0, 1))) + 0.05 else 1)
  91. }
  92. }
  93. }
  94.  
  95. // -- End collision detection
  96.  
  97. i += 1
  98. }
  99.  
  100. lazy val sky = { // Sky
  101. val c = 200 + (100 * Math.atan(vector.normalize.z) / (Math.PI / 2)).toInt
  102. new Color(50, 150, Math.max(Math.min(c, 255), 0))
  103. }
  104.  
  105. var finalColor = color.getOrElse(sky)
  106. val floats = Array.ofDim[Float](3)
  107. Color.RGBtoHSB(finalColor.getRed, finalColor.getGreen, finalColor.getBlue, floats)
  108. finalColor = Color.getHSBColor(floats(0), floats(1), Math.max(floats(2) - darkness.toFloat * 0.2f, 0))
  109.  
  110. image.setRGB(x, y, finalColor.getRGB)
  111. }
  112.  
  113. ImageIO.write(image, "png", new File("ray.png"))
  114. g.dispose()
  115. }
  116.  
  117. val quality: Int = 1 // 1: a few seconds on a multicore processor / 4: max quality, more than a minute
  118.  
  119. rayTracing(500 * quality, 300 * quality, 200, Point(10, -2, 100), Vector(100, 120, 0))
  120.  
  121. }
Add Comment
Please, Sign In to add comment