diff --git a/src/main.go b/src/main.go deleted file mode 100644 index 1868e3b..0000000 --- a/src/main.go +++ /dev/null @@ -1,134 +0,0 @@ -package main - -// RIGHT : x -// FORWARD : Y -// UP : Z - -import ( - "fmt" - "math" - "runtime" - "sync" - - rl "github.com/gen2brain/raylib-go/raylib" -) - -const WIDTH = 100 -const HEIGHT = 100 -const TEXTURE_SCALE = 4 - -const MAX_DIST = 500.0 -const MAX_STEP = 100 -const EPS = 0.1 -const PI = math.Pi - -const SOFT_SHADOW_COEFF = 16 - -var lightPos Vector3 -var scene SDF - -// radius, theta, phi -var screenSpherical Vector3 -var screenPhysicalSize float64 -var cameraPos Vector3 - -var sphere TranslatedSDF - -func init() { - lightPos = Vector3{100, -400, 400} - - cameraPos = Vector3{0, -10, 25} - screenSpherical = Vector3{10, PI/2 + 0.2, PI / 2} - screenPhysicalSize = 5 -} - -func update(t float64) { - - sphereMat := RED_MAT - sphereMat.specularFac = 0.5 - sphere = TranslatedSDF{Sphere{10, sphereMat}, Vector3{0, 100, 10}} - - // boxMat := BLUE_MAT - // box := TranslatedSDF{Box{Vector3{10, 2, 10}, boxMat}, Vector3{0, 100, 10}} - // sphere := RepeatSDF{Sphere{20, sphereMat}, Vector3{50, 50, 50}} - plane := Plane{Vector3{0, 0, 1}, WHITE_GREY_GRID_MAT} - - sphere.translate.Z = 20 * math.Sin(t) - scene = SmoothUnionSDF{sphere, plane, 2.5} - // scene = UnionSDF{plane, sphere} -} - -func compute_pixel(y0 int, y1 int, wg *sync.WaitGroup, screenCenter Vector3, phiVec Vector3, thetaVec Vector3, image *rl.Image) { - defer wg.Done() - - for pixelY := y0; pixelY < y1; pixelY++ { - for pixelX := range WIDTH { - sx := screenPhysicalSize * (float64(pixelX)/WIDTH - 0.5) - sy := screenPhysicalSize * (float64(pixelY)/HEIGHT - 0.5) - - origin := screenCenter.Add(phiVec.Scale(-sx)).Add(thetaVec.Scale(sy)) - direction := (origin.Sub(cameraPos)).Normalized() - - hit, colorVec := rayMarch(origin, direction) - var fr, fg, fb float64 - if hit { - fr, fg, fb = colorVec.Unpack() - } else { - fr, fg, fb = 0, 0, 0 - } - fr, fg, fb = Clamp(fr, 0, 255), Clamp(fg, 0, 255), Clamp(fb, 0, 255) - r, g, b := uint8(fr), uint8(fg), uint8(fb) - - rl.ImageDrawPixel(image, int32(pixelX), int32(pixelY), rl.Color{R: r, G: g, B: b, A: 255}) - } - } -} -func genImage() *rl.Image { - screenCartesian, _, thetaVec, phiVec := screenSpherical.SphericalToCartesian() - screenCenter := cameraPos.Add(screenCartesian) - - image := rl.GenImageColor(WIDTH, HEIGHT, rl.Black) - - // numWorkers := 1 - numWorkers := runtime.NumCPU() - - var wg sync.WaitGroup - wg.Add(numWorkers) - - bandHeight := HEIGHT / numWorkers - - for worker := range numWorkers { - startY := worker * bandHeight - endY := startY + bandHeight - if worker == numWorkers-1 { - endY = HEIGHT - } - - go compute_pixel(startY, endY, &wg, screenCenter, phiVec, thetaVec, image) - } - - wg.Wait() - return image -} - -func main() { - rl.InitWindow(WIDTH*TEXTURE_SCALE, HEIGHT*TEXTURE_SCALE, "raymarching") - var texture rl.Texture2D - time := rl.GetTime() - t := 0.0 - - for !rl.WindowShouldClose() { - new_time := rl.GetTime() - dt := new_time - time - t += dt - time = new_time - - update(t) - fmt.Println("FPS ", 1/dt) - rl.BeginDrawing() - rl.ClearBackground(rl.Black) - texture = rl.LoadTextureFromImage(genImage()) - rl.DrawTextureEx(texture, rl.Vector2{X: 0, Y: 0}, 0.0, TEXTURE_SCALE, rl.White) - rl.EndDrawing() - } -} diff --git a/src/ray_marching.go b/src/ray_marching.go index d7b806f..0dc2551 100644 --- a/src/ray_marching.go +++ b/src/ray_marching.go @@ -6,8 +6,51 @@ package main import ( "math" + "runtime" + "sync" + + rl "github.com/gen2brain/raylib-go/raylib" ) +const MAX_DIST = 1000.0 +const MAX_STEP = 1000 +const EPS = 0.01 +const WIDTH = 500 +const HEIGHT = 500 +const PI = math.Pi + +const SOFT_SHADOW_COEFF = 32 + +var lightPos Vector3 +var scene SDF + +// radius, theta, phi +var screenSpherical Vector3 +var screenPhysicalSize float64 +var cameraPos Vector3 + +func init() { + lightPos = Vector3{100, -400, 400} + + cameraPos = Vector3{0, -10, 25} + screenSpherical = Vector3{10, PI/2 + 0.2, PI / 2} + screenPhysicalSize = 5 + + sphereMat := RED_MAT + sphereMat.specularFac = 0.5 + sphere := TranslatedSDF{Sphere{10, sphereMat}, Vector3{0, 100, 10}} + + // boxMat := BLUE_MAT + // box := TranslatedSDF{Box{Vector3{10, 2, 10}, boxMat}, Vector3{0, 100, 10}} + + // sphere := RepeatSDF{Sphere{20, sphereMat}, Vector3{50, 50, 50}} + plane := Plane{Vector3{0, 0, 1}, WHITE_GREY_GRID_MAT} + + scene = SmoothUnionSDF{sphere, plane, 2.5} + // scene = UnionSDF{plane, sphere} + +} + func phongShading(point Vector3, normal Vector3, mat Material) Vector3 { lightVec := (lightPos.Sub(point)).Normalized() reflectLight := Reflect(lightVec, normal) @@ -59,3 +102,65 @@ func rayMarch(origin Vector3, direction Vector3) (bool, Vector3) { } return false, GREY } + +func genImage() *rl.Image { + screenCartesian, _, thetaVec, phiVec := screenSpherical.SphericalToCartesian() + screenCenter := cameraPos.Add(screenCartesian) + + image := rl.GenImageColor(WIDTH, HEIGHT, rl.Black) + + numWorkers := runtime.NumCPU() + var wg sync.WaitGroup + wg.Add(numWorkers) + + bandHeight := HEIGHT / numWorkers + + for worker := range numWorkers { + startY := worker * bandHeight + endY := startY + bandHeight + if worker == numWorkers-1 { + endY = HEIGHT + } + + go func(y0, y1 int) { + defer wg.Done() + + for pixelY := y0; pixelY < y1; pixelY++ { + for pixelX := range WIDTH { + sx := screenPhysicalSize * (float64(pixelX)/WIDTH - 0.5) + sy := screenPhysicalSize * (float64(pixelY)/HEIGHT - 0.5) + + origin := screenCenter.Add(phiVec.Scale(-sx)).Add(thetaVec.Scale(sy)) + direction := (origin.Sub(cameraPos)).Normalized() + + hit, colorVec := rayMarch(origin, direction) + var fr, fg, fb float64 + if hit { + fr, fg, fb = colorVec.Unpack() + } else { + fr, fg, fb = 0, 0, 0 + } + fr, fg, fb = Clamp(fr, 0, 255), Clamp(fg, 0, 255), Clamp(fb, 0, 255) + r, g, b := uint8(fr), uint8(fg), uint8(fb) + + rl.ImageDrawPixel(image, int32(pixelX), int32(pixelY), rl.Color{R: r, G: g, B: b, A: 255}) + } + } + }(startY, endY) + } + + wg.Wait() + return image +} + +func main() { + rl.InitWindow(WIDTH, HEIGHT, "raymarching") + texture := rl.LoadTextureFromImage(genImage()) + + for !rl.WindowShouldClose() { + rl.BeginDrawing() + rl.ClearBackground(rl.Black) + rl.DrawTexture(texture, 0, 0, rl.White) + rl.EndDrawing() + } +}