From VisualWorks® NonCommercial, 7.4.1 of May 30, 2006 on September 20, 2007 at 7:53:34 pm Ray Smalltalk Core.Object false none orig dir RayBench (none) RayBench Smalltalk Core.Object false none RayBench (none) Hit Smalltalk Core.Object false none lambda normal RayBench (none) Sphere Smalltalk Core.Object false none center radius RayBench (none) Group Smalltalk Core.Object false none bound objs RayBench (none) Vec Smalltalk Core.Object false none x y z RayBench (none) Ray class instance creation orig: o dir: d ^self new setOrig: o dir: d; yourself Ray accessing dir ^dir orig ^orig Ray private setOrig: o dir: d orig := o. dir := d RayBench class example pixelSize: px level: level "Time millisecondsToRun: [self pixelSize: 64 level: 4]" | scene out lf pxStr ss | ss := 4. scene := self createLevel: level center: #(0d -1d 1d) asVec radius: 1d. out := 'image.pgm' asFilename writeStream. lf := String with: Character lf. pxStr := px printString. out nextPutAll: ('P5', lf, pxStr, ' ', pxStr, lf, '255', lf); binary. px - 1 to: 0 by: -1 do: [:y | 0 to: px - 1 do: [:x | | gain | gain := 0d. 0 to: ss - 1 do: [:dx | 0 to: ss - 1 do: [:dy | | eye dir | dir := Vec x: x + (dx asDouble / ss) - (px / 2) y: y + (dy asDouble / ss) - (px / 2) z: px. eye := Ray orig: #(0d 0d -4d) asVec dir: dir unitise. gain := gain + (self rayTraceLight: #(-1d -3d 2d) asVec unitise ray: eye scene: scene)]]. out nextPut: (255 * gain / (ss * ss)) rounded]]. out close RayBench class private createLevel: level center: position radius: radius | sphere group factor | sphere := Sphere center: position radius: radius. level = 1 ifTrue: [^sphere]. group := Group bound: (Sphere center: position radius: 3d * radius). group objs add: sphere. factor := 3d * radius / 12 sqrt. #(-1 1) do: [:dx | #(-1 1) do: [:dz | | childPos | childPos := position + ((Vec x: dx y: 1 z: dz) * factor). group objs add: (self createLevel: level - 1 center: childPos radius: radius / 2d)]]. ^group rayTraceLight: light ray: camRay scene: scene | hit refPos spGai spRay spHit delta infinity zeroVec | delta := 2.22045e-16 sqrt. infinity := 1d308. zeroVec := Vec x: 0d y: 0d z: 0d. hit := scene intersectHit: (Hit lambda: infinity normal: zeroVec) ray: camRay. hit lambda = infinity ifTrue: [^0]. refPos := camRay orig + (camRay dir * hit lambda) + (hit normal * delta). spGai := light dot: hit normal. spGai >= 0 ifTrue: [^0]. spRay := Ray orig: refPos dir: (light * -1). spHit := scene intersectHit: (Hit lambda: infinity normal: zeroVec) ray: spRay. ^spHit lambda = infinity ifTrue: [spGai negated] ifFalse: [0] Core.Array converting asVec ^Vec newFrom: self Hit class instance creation lambda: l normal: n ^self new setLambda: l normal: n; yourself Hit accessing lambda ^lambda normal ^normal Hit private setLambda: l normal: n lambda := l. normal := n Sphere class instance creation center: c radius: r ^self new setCenter: c radius: r; yourself Sphere accessing center ^center radius ^radius Sphere processing intersectHit: hit ray: ray | len vec | len := self raySphere: ray. len >= hit lambda ifTrue: [^hit]. vec := ray orig + (ray dir * len - center). ^Hit lambda: len normal: vec unitise raySphere: ray | vec b det sqDet t2 t1 | vec := center - ray orig. b := vec dot: ray dir. det := b * b - (vec dot: vec) + (radius * radius). det < 0 ifTrue: [^1d308]. sqDet := det sqrt. t2 := b + sqDet. t2 < 0 ifTrue: [^1d308]. t1 := b - sqDet. ^t1 > 0 ifTrue: [t1] ifFalse: [t2] Sphere private setCenter: c radius: r center := c. radius := r Group class instance creation bound: aSphere ^self new initialize; setBound: aSphere; yourself Group private setBound: aSphere bound := aSphere Group accessing objs ^objs Group processing intersectHit: hit ray: ray | len | len := bound raySphere: ray. len >= hit lambda ifTrue: [^hit]. ^objs inject: hit into: [:h :ss | ss intersectHit: h ray: ray] Group initialize-release initialize objs := OrderedCollection new release objs := nil. super release Vec class instance creation newFrom: array ^self x: (array at: 1) y: (array at: 2) z: (array at: 3) x: x y: y z: z ^self new setX: x y: y z: z; yourself Vec arithmetic * scale ^self class x: (x * scale) y: (y * scale) z: (z * scale) + other ^self class x: (x + other x) y: (y + other y) z: (z + other z) - other ^self class x: (x - other x) y: (y - other y) z: (z - other z) dot: other ^(x * other x) + (y * other y) + (z * other z) unitise ^self * (1 / (self dot: self) sqrt) Vec private setX: newX y: newY z: newZ x := newX. y := newY. z := newZ Vec accessing x ^x y ^y z ^z