-
-
Save abhi-jha/46efcb25ad2effcb1ce9d5f68c028eda to your computer and use it in GitHub Desktop.
Ascii Raymarcher(old)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #include <stdint.h> | |
| #include <math.h> | |
| #include <algorithm> | |
| #include <string> | |
| #ifdef _WIN32 | |
| #define NOMINMAX | |
| #include <Windows.h> | |
| #include <fstream> | |
| void CaptureScreen(HWND window, const char* filename) | |
| { | |
| RECT windowRect; | |
| GetWindowRect(window, &windowRect); | |
| int bitmap_dx = windowRect.right - windowRect.left; | |
| int bitmap_dy = windowRect.bottom - windowRect.top; | |
| std::ofstream file(filename, std::ios::binary); | |
| if( !file ) return; | |
| BITMAPFILEHEADER fileHeader; | |
| BITMAPINFOHEADER infoHeader; | |
| fileHeader.bfType = 0x4d42; | |
| fileHeader.bfSize = 0; | |
| fileHeader.bfReserved1 = 0; | |
| fileHeader.bfReserved2 = 0; | |
| fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); | |
| infoHeader.biSize = sizeof(infoHeader); | |
| infoHeader.biWidth = bitmap_dx; | |
| infoHeader.biHeight = bitmap_dy; | |
| infoHeader.biPlanes = 1; | |
| infoHeader.biBitCount = 24; | |
| infoHeader.biCompression = BI_RGB; | |
| infoHeader.biSizeImage = 0; | |
| infoHeader.biXPelsPerMeter = 0; | |
| infoHeader.biYPelsPerMeter = 0; | |
| infoHeader.biClrUsed = 0; | |
| infoHeader.biClrImportant = 0; | |
| file.write((char*)&fileHeader, sizeof(fileHeader)); | |
| file.write((char*)&infoHeader, sizeof(infoHeader)); | |
| BITMAPINFO info; | |
| info.bmiHeader = infoHeader; | |
| HDC winDC = GetWindowDC(window); | |
| HDC memDC = CreateCompatibleDC(winDC); | |
| BYTE* memory = 0; | |
| HBITMAP bitmap = CreateDIBSection(winDC, &info, DIB_RGB_COLORS, (void**)&memory, 0, 0); | |
| SelectObject(memDC, bitmap); | |
| BitBlt(memDC, 0, 0, bitmap_dx, bitmap_dy, winDC, 0, 0, SRCCOPY); | |
| DeleteDC(memDC); | |
| ReleaseDC(window, winDC); | |
| int bytes = (((24 * bitmap_dx + 31) & (~31)) / 8)*bitmap_dy; | |
| file.write((const char*)memory, bytes); | |
| DeleteObject(bitmap); | |
| } | |
| #endif | |
| typedef float Real; | |
| #define USE_SSE | |
| #ifdef USE_SSE | |
| #include <pmmintrin.h> | |
| // simd modulo | |
| inline __m128 _mm_mod_ps2(const __m128& a, const __m128& aDiv) | |
| { | |
| __m128 c = _mm_div_ps(a, aDiv); | |
| __m128i i = _mm_cvttps_epi32(c); | |
| __m128 cTrunc = _mm_cvtepi32_ps(i); | |
| __m128 base = _mm_mul_ps(cTrunc, aDiv); | |
| __m128 r = _mm_sub_ps(a, base); | |
| return r; | |
| } | |
| #endif | |
| union Vec3 | |
| { | |
| #ifdef USE_SSE | |
| __m128 SimdReals; | |
| Vec3(__m128 Vec) | |
| : | |
| SimdReals(Vec) | |
| { | |
| } | |
| #endif | |
| Vec3(Real X, Real Y, Real Z) | |
| : | |
| X(X), Y(Y), Z(Z) | |
| { | |
| } | |
| Real Reals[3]; | |
| struct | |
| { | |
| Real X, Y, Z; | |
| }; | |
| Real Length() const | |
| { | |
| #ifdef USE_SSE | |
| return static_cast<Real>(_mm_cvtss_f32(_mm_sqrt_ss(_mm_dp_ps(SimdReals, SimdReals, 0x71)))); | |
| #else | |
| return static_cast<Real>( | |
| sqrt(X*X + Y*Y + Z*Z) | |
| ); | |
| #endif | |
| } | |
| Vec3 Normalized() const | |
| { | |
| #ifdef USE_SSE | |
| return Vec3{ _mm_mul_ps( | |
| this->SimdReals, _mm_rsqrt_ps( | |
| _mm_dp_ps( | |
| this->SimdReals, this->SimdReals, 0x7f))) | |
| }; | |
| #else | |
| const Real Len = Length(); | |
| return (*this) / Len; | |
| #endif | |
| } | |
| Real Dot(const Vec3& Other) const | |
| { | |
| #ifdef USE_SSE | |
| return static_cast<Real>( | |
| _mm_cvtss_f32( | |
| _mm_dp_ps(SimdReals, Other.SimdReals, 0x71) | |
| ) | |
| ); | |
| #else | |
| return X * Other.X + Y * Other.Y + Z * Other.Z; | |
| #endif | |
| } | |
| Vec3 Abs() const | |
| { | |
| return Vec3{ | |
| abs(X), | |
| abs(Y), | |
| abs(Z) | |
| }; | |
| } | |
| Vec3 operator + (const Vec3& Other) const | |
| { | |
| #ifdef USE_SSE | |
| return Vec3{ _mm_add_ps(SimdReals, Other.SimdReals) }; | |
| #else | |
| return Vec3{ | |
| X + Other.X, | |
| Y + Other.Y, | |
| Z + Other.Z }; | |
| #endif | |
| } | |
| Vec3 operator - (const Vec3& Other) const | |
| { | |
| #ifdef USE_SSE | |
| return Vec3{ _mm_sub_ps(SimdReals,Other.SimdReals) }; | |
| #else | |
| return Vec3{ | |
| X - Other.X, | |
| Y - Other.Y, | |
| Z - Other.Z | |
| }; | |
| #endif | |
| } | |
| Vec3 operator * (const Vec3& Other) const | |
| { | |
| #ifdef USE_SSE | |
| return Vec3{ _mm_mul_ps(SimdReals,Other.SimdReals) }; | |
| #else | |
| return Vec3{ | |
| X * Other.X, | |
| Y * Other.Y, | |
| Z * Other.Z | |
| }; | |
| #endif | |
| } | |
| Vec3 operator / (const Vec3& Other) const | |
| { | |
| #ifdef USE_SSE | |
| return Vec3{ _mm_div_ps(SimdReals,Other.SimdReals) }; | |
| #else | |
| return Vec3{ | |
| X / Other.X, | |
| Y / Other.Y, | |
| Z / Other.Z | |
| }; | |
| #endif | |
| } | |
| Vec3 operator % (const Vec3& Other) const | |
| { | |
| #ifdef USE_SSE | |
| return Vec3{ _mm_mod_ps2(SimdReals,Other.SimdReals) }; | |
| #else | |
| return Vec3{ | |
| fmod(X,Other.X), | |
| fmod(Y,Other.Y), | |
| fmod(Z,Other.Z) | |
| }; | |
| #endif | |
| } | |
| Vec3 operator + (const Real& Other) const | |
| { | |
| #ifdef USE_SSE | |
| return Vec3{ _mm_add_ps(SimdReals,_mm_set1_ps(Other)) }; | |
| #else | |
| return Vec3{ | |
| X + Other, | |
| Y + Other, | |
| Z + Other | |
| }; | |
| #endif | |
| } | |
| Vec3 operator - (const Real& Other) const | |
| { | |
| #ifdef USE_SSE | |
| return Vec3{ _mm_sub_ps(SimdReals,_mm_set1_ps(Other)) }; | |
| #else | |
| return Vec3{ | |
| X - Other, | |
| Y - Other, | |
| Z - Other | |
| }; | |
| #endif | |
| } | |
| Vec3 operator * (const Real& Other) const | |
| { | |
| #ifdef USE_SSE | |
| return Vec3{ _mm_mul_ps(SimdReals,_mm_set1_ps(Other)) }; | |
| #else | |
| return Vec3{ | |
| X * Other, | |
| Y * Other, | |
| Z * Other | |
| }; | |
| #endif | |
| } | |
| Vec3 operator / (const Real& Other) const | |
| { | |
| #ifdef USE_SSE | |
| return Vec3{ _mm_div_ps(SimdReals,_mm_set1_ps(Other)) }; | |
| #else | |
| return Vec3{ | |
| X / Other, | |
| Y / Other, | |
| Z / Other | |
| }; | |
| #endif | |
| } | |
| Vec3 operator % (const Real& Other) const | |
| { | |
| #ifdef USE_SSE | |
| return Vec3{ _mm_mod_ps2(SimdReals,_mm_set1_ps(Other)) }; | |
| #else | |
| return Vec3{ | |
| fmod(X,Other), | |
| fmod(Y , Other), | |
| fmod(Z , Other) | |
| }; | |
| #endif | |
| } | |
| }; | |
| namespace Shapes | |
| { | |
| Real Plane(const Vec3& Position, const Vec3& Normal) | |
| { | |
| return Position.Dot(Normal.Normalized()); | |
| //return Position.Y; | |
| } | |
| Real Sphere(const Vec3& Position, Real Radius) | |
| { | |
| return Position.Length() - Radius; | |
| } | |
| Real Box(const Vec3& Position, Vec3 Bounds) | |
| { | |
| Vec3 Dist = Position.Abs() - Bounds; | |
| return std::min<Real>(std::max(Dist.X, std::max<Real>(Dist.Y, Dist.Z)), 0.0) + | |
| Vec3{ std::max<Real>(Dist.X,0.0), | |
| std::max<Real>(Dist.Y,0.0), | |
| std::max<Real>(Dist.Z,0.0) }.Length(); | |
| } | |
| Real RoundBox(const Vec3& Position, Vec3 Bounds, Real Radius) | |
| { | |
| return Box(Position, Bounds) - Radius; | |
| } | |
| Real Capsule(const Vec3& Position, Vec3 A, Vec3 B, Real Radius) | |
| { | |
| Vec3 Pa = Position - A; | |
| Vec3 Ba = B - A; | |
| Real H = (Pa.Dot(Ba) / Ba.Dot(Ba)); | |
| H = std::min<Real>(0, std::max<Real>(1.0, H)); | |
| return (Pa - (Ba*H)).Length() - Radius; | |
| } | |
| Real Torus(const Vec3& Position, Real InRadius, Real OutRadius) | |
| { | |
| Vec3 Q{ Vec3{Position.X,Position.Z,0}.Length() - OutRadius,Position.Y,0 }; | |
| return Q.Length() - InRadius; | |
| } | |
| } | |
| namespace Operations | |
| { | |
| Real Union(Real A, Real B) | |
| { | |
| return std::min(A, B); | |
| } | |
| Real SmoothUnion(Real A, Real B, Real K = 8) | |
| { | |
| /* | |
| Power Smooth | |
| A = std::pow(A, K); | |
| B = std::pow(B, K); | |
| return std::pow((A*B) / (A + B), Real(1) / K); | |
| */ | |
| Real H = std::min<Real>(0, std::max<Real>(1, Real(0.5) + Real(0.5)*(B - A) / K)); | |
| return (B * (Real(1.0) - H) + A*H) - (K*H*(Real(1.0) - H)); | |
| } | |
| Real Intersection(Real A, Real B) | |
| { | |
| return std::max(A, B); | |
| } | |
| Real Subtract(Real A, Real B) | |
| { | |
| return Intersection(-A, B); | |
| } | |
| } | |
| namespace Translate | |
| { | |
| const static Real Pi(static_cast<Real>(3.1415926535897932384626433)); | |
| Vec3 RotX(const Vec3& Position, Real Angle) | |
| { | |
| Angle *= Pi / Real(180); | |
| return Vec3{ | |
| Position.X, | |
| Position.Y * cos(Angle) - Position.Z * sin(Angle), | |
| Position.Y * sin(Angle) + Position.Z * cos(Angle), | |
| }; | |
| } | |
| Vec3 RotY(const Vec3& Position, Real Angle) | |
| { | |
| Angle *= Pi / Real(180); | |
| return Vec3{ | |
| Position.Z * sin(Angle) + Position.X * cos(Angle), | |
| Position.Y, | |
| Position.Z * cos(Angle) - Position.X * sin(Angle), | |
| }; | |
| } | |
| Vec3 RotZ(const Vec3& Position, Real Angle) | |
| { | |
| Angle *= Pi / Real(180); | |
| return Vec3{ | |
| Position.X * cos(Angle) - Position.Y * sin(Angle), | |
| Position.X * sin(Angle) + Position.Y * cos(Angle), | |
| Position.Z, | |
| }; | |
| } | |
| } | |
| #define WIDTH (79) | |
| #define HEIGHT (39) | |
| #define PREC 0.002 | |
| static size_t Tick = 0; | |
| //// SCENE | |
| Real Scene(const Vec3& Point) | |
| { | |
| Real Distance = 0; | |
| Distance = Shapes::Plane(Point, Vec3{ 0,1,0 }); | |
| Distance = Operations::Union( | |
| Distance, | |
| Shapes::Sphere(Point, 1.0) | |
| ); | |
| Distance = Operations::Union( | |
| Distance, | |
| Shapes::RoundBox(Translate::RotZ(Point - Vec3{ -5,2,5 }, Real(15 + Tick * 15)), | |
| Vec3{ 1,2,1 }, 0.525f) | |
| ); | |
| Distance = Operations::Union( | |
| Distance, | |
| Shapes::Capsule(Point, | |
| Vec3{ 5,5,6 }, | |
| Vec3{ -5,5,6 }, | |
| Real(3.75) | |
| )); | |
| Distance = Operations::Union( | |
| Distance, | |
| Shapes::Torus(Translate::RotX(Point - Vec3{ 0,Real(0.5),12 }, 45), | |
| Real(1), Real(6) | |
| )); | |
| for( size_t i = 1; i < 8; i++ ) | |
| { | |
| Distance = Operations::Union( | |
| Distance, | |
| Shapes::Torus( | |
| Translate::RotZ(Translate::RotX(Point - Vec3{ 0,Real(0.5),Real(12 + i * 7) }, 85), Real(i * 30 + (Tick * 5))), | |
| Real(1), Real(6) | |
| )); | |
| } | |
| return Distance; | |
| } | |
| Vec3 CalcNormal(const Vec3& Point) | |
| { | |
| #define EPSILON static_cast<Real>(0.001) | |
| return Vec3{ | |
| Scene(Point + Vec3{ EPSILON,0,0}) - Scene(Point - Vec3{ EPSILON,0,0 }), | |
| Scene(Point + Vec3{ 0,EPSILON,0 }) - Scene(Point - Vec3{ 0,EPSILON,0 }), | |
| Scene(Point + Vec3{ 0,0,EPSILON }) - Scene(Point - Vec3{ 0,0,EPSILON }), | |
| }.Normalized(); | |
| } | |
| Real March(const Vec3& Origin, const Vec3& Ray, bool* Hit) | |
| { | |
| Real Distance = 0; | |
| for( size_t i = 0; i < 128; i++ ) | |
| { | |
| Real ClosestSurface = Scene(Origin + (Ray * Distance)); | |
| if( ClosestSurface < PREC ) | |
| { | |
| // "Hit" a surface | |
| if( Hit != nullptr ) | |
| { | |
| *Hit = true; | |
| } | |
| break; | |
| } | |
| Distance += ClosestSurface * Real(0.75); | |
| } | |
| return Distance; | |
| } | |
| Real Shadow(const Vec3& LightPos, const Vec3& LightDir, Real Min, Real Max, Real K) | |
| { | |
| Real Res = 1; | |
| for( Real t = Min; t < Max;) | |
| { | |
| Real Distance = Scene(LightPos + LightDir*t); | |
| if( Distance < PREC ) | |
| { | |
| return 0.0; | |
| } | |
| Res = std::min(Res, K*Distance / t); | |
| t += Distance; | |
| } | |
| return Res; | |
| } | |
| const char Shades[] = ".:*oe&$#%@"; | |
| #include <float.h> | |
| int main() | |
| { | |
| //_controlfp_s(nullptr, _EM_INEXACT, _MCW_EM); | |
| Vec3 LightDir = Vec3{ 1,1,0 }.Normalized(); | |
| Vec3 EyePos = Vec3{ 0,2,-6 }; | |
| std::string Screen; | |
| Screen.reserve(WIDTH * HEIGHT); | |
| do | |
| { | |
| EyePos.Z += Real(2); | |
| Tick++; | |
| for( size_t y = 0; y < HEIGHT; y++ ) | |
| { | |
| for( size_t x = 0; x < WIDTH; x++ ) | |
| { | |
| Vec3 UV{ | |
| static_cast<Real>(x), | |
| static_cast<Real>(y), | |
| 1 }; | |
| UV = UV / Vec3{ | |
| WIDTH, | |
| HEIGHT, | |
| 1 }; | |
| // Recanonicalize [-1,1] | |
| UV = (UV * 2.0) - 1.0; | |
| // Flip Y axis | |
| UV.Y *= Real(-1); | |
| // Aspect Ratio Correction | |
| UV.X *= WIDTH / HEIGHT; | |
| //UV.X *= 0.75; | |
| // Fov | |
| UV.Z = Real(2); | |
| bool Hit = false; | |
| Real Distance = March(EyePos, UV.Normalized(), &Hit); | |
| Vec3 Point = EyePos + (UV.Normalized() * Distance); | |
| if( Hit ) | |
| { | |
| Vec3 Normal = CalcNormal(Point); | |
| Real Diffuse = Normal.Dot(LightDir); | |
| Diffuse *= 0.5; | |
| Diffuse += 0.5; | |
| Diffuse *= Diffuse; | |
| Diffuse *= Shadow(Point, LightDir, Real(0.5), 10, 10); | |
| if( std::isfinite(Diffuse) ) | |
| { | |
| Screen += Shades[static_cast<size_t>(Diffuse*(sizeof(Shades) - 2))]; | |
| } | |
| else | |
| { | |
| Screen += '!'; | |
| } | |
| } | |
| else | |
| { | |
| Screen += ' '; | |
| } | |
| } | |
| Screen += "\n"; | |
| } | |
| printf("%s", Screen.c_str()); | |
| // Screenshot | |
| #ifdef _WIN32 | |
| //CaptureScreen(GetForegroundWindow(), (std::to_string(Tick) + ".bmp").c_str()); | |
| #endif | |
| Screen.clear(); | |
| } while( /*getchar() != 'q'*/ Tick < 200 ); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment