Ascii Raymarcher(old)
This file contains 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 <math.h> | |
#include <algorithm> | |
#include <string> | |
#include <immintrin.h> | |
using namespace std;typedef float R; | |
#define _W 79 | |
#define _H 39 | |
#define EP 0.01f | |
#define OP operator | |
#define C const | |
#define E return | |
#define PQ M*(3.1415f/180) | |
union J{__m128 V;J(__m128 V):V(V){}J(R X,R Y,R Z):X(X),Y(Y),Z(Z){}struct{R X,Y,Z;};R L()C{E _mm_cvtss_f32(_mm_sqrt_ss(_mm_dp_ps(V,V,0x71)));}J N()C{E _mm_mul_ps(V,_mm_rsqrt_ps(_mm_dp_ps(V,V,0x7f)));}R D(C J& O)C{E _mm_cvtss_f32(_mm_dp_ps(V,O.V,0x71));}J A()C{E J{abs(X),abs(Y),abs(Z)};}J OP+(C J& O)C{E _mm_add_ps(V,O.V);}J OP-(C J& O)C{E _mm_sub_ps(V,O.V);}J OP*(C J& O)C{E _mm_mul_ps(V,O.V);}J OP/(C J& O)C{E _mm_div_ps(V,O.V);}J OP+(C R& O)C{E _mm_add_ps(V,_mm_set1_ps(O));}J OP-(C R& O)C{E _mm_sub_ps(V,_mm_set1_ps(O));}J OP*(C R& O)C{E J{_mm_mul_ps(V,_mm_set1_ps(O))};}};R BX(C J& P,J B){J D=P.A()-B;E min(max(D.X,max(D.Y, D.Z)),.0f)+J{max(D.X,.0f),max(D.Y,.0f),max(D.Z,0.0f)}.L();}R RB(C J& P,J B,R R){E BX(P,B)-R;}J RY(C J& P,R A){E J{P.Z*sin(A)+P.X*cos(A),P.Y,P.Z*cos(A)-P.X*sin(A),};}J RZ(C J& P,R A){E J{P.X*cos(A)-P.Y*sin(A),P.X*sin(A)+P.Y*cos(A),P.Z,};}static size_t M=0;R Q(C J& P){R D=P.Y+2;D=min(D,RB(RY(RZ(P,PQ),PQ),J{2,2,2},0.5f));E D;}J Nor(C J& P){E J{Q(P+J{EP,0,0})-Q(P-J{EP,0,0}),Q(P+J{0,EP,0})-Q(P-J{0,EP,0}),Q(P+J{0,0,EP})-Q(P-J{0,0,EP}),}.N();}R Y(C J& O,C J& D,bool* H){R T=0;for(size_t i=0;i<128;i++){R Y=Q(O+(D*T));if(Y<EP){*H=1;break;}T+=Y;}E T;}R B(C J& O,C J& D,R U,R I,R K){R S=1;for(R t=U;t<I;){R di=Q(O+D*t);if(di<EP){E 0;}S=min(S,K*di/t);t+=di;}E S;}int main(){J LD=J{0.5,1,0.25}.N();J G=J{0,1,-8};string S;S.reserve(_W*_H);do{M++;for(size_t y=0;y<_H;y++){for(size_t x=0;x<_W;x++){J K(x,y,1);K=K/J(_W,_H,1);K=(K*2.0)-1;K.Y=-K.Y;K.X*=_W/_H;K.Z=R(1/0.726);K=K.N();bool H=0;R Z=Y(G,K,&H);J P=G+(K*Z);if(H){J N=Nor(P);R D=N.D(LD);D*=0.5;D+=0.5;D*=D;D*=B(P,LD,R(0.5),10,10);S+=".:*oe$&#%@"[static_cast<size_t>(D*10)];}else{S+=' ';}}S+="\n";}printf("%s",S.c_str());S.clear();}while(M<360);E 0;} |
This file contains 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 WindowBounds; | |
GetWindowRect(Window, &WindowBounds); | |
int Width = WindowBounds.right - WindowBounds.left; | |
int Height = WindowBounds.bottom - WindowBounds.top; | |
std::ofstream fOut(filename, std::ios::binary); | |
if( !fOut ) return; | |
BITMAPFILEHEADER BmpHeader; | |
BITMAPINFOHEADER InfoHeader; | |
BmpHeader.bfType = 0x4d42; | |
BmpHeader.bfSize = 0; | |
BmpHeader.bfReserved1 = 0; | |
BmpHeader.bfReserved2 = 0; | |
BmpHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); | |
InfoHeader.biSize = sizeof(InfoHeader); | |
InfoHeader.biWidth = Width; | |
InfoHeader.biHeight = Height; | |
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; | |
fOut.write((char*)&BmpHeader, sizeof(BmpHeader)); | |
fOut.write((char*)&InfoHeader, sizeof(InfoHeader)); | |
BITMAPINFO BmpInfo; | |
BmpInfo.bmiHeader = InfoHeader; | |
HDC winDC = GetWindowDC(Window); | |
HDC memDC = CreateCompatibleDC(winDC); | |
BYTE* Buffer = 0; | |
HBITMAP ImageDC = CreateDIBSection(winDC, &BmpInfo, DIB_RGB_COLORS, (void**)&Buffer, 0, 0); | |
SelectObject(memDC, ImageDC); | |
BitBlt(memDC, 0, 0, Width, Height, winDC, 0, 0, SRCCOPY); | |
DeleteDC(memDC); | |
ReleaseDC(Window, winDC); | |
size_t Size = (((24 * Width + 31) & (~31)) / 8)*Height; | |
fOut.write((const char*)Buffer, Size); | |
DeleteObject(ImageDC); | |
} | |
#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& Divisor) | |
{ | |
__m128 C = _mm_div_ps(A, Divisor); | |
__m128i I = _mm_cvttps_epi32(C); | |
__m128 Trunc = _mm_cvtepi32_ps(I); | |
__m128 Base = _mm_mul_ps(Trunc, Divisor); | |
__m128 Remainder = _mm_sub_ps(A, Base); | |
return Remainder; | |
} | |
#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()); | |
} | |
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 Clamp(Real A, Real Min, Real Max) | |
{ | |
const Real T = A < Min ? Min : A; | |
return T > Max ? Max : T; | |
} | |
Real Lerp(Real A, Real B, Real T) | |
{ | |
return std::fma(T, B, std::fma(-T, A, A)); | |
} | |
Real Union(Real A, Real B) | |
{ | |
return std::min(A, B); | |
} | |
Real SmoothUnion(Real A, Real B, Real K = 1) | |
{ | |
/* | |
Power Smooth | |
A = std::pow(A, K); | |
B = std::pow(B, K); | |
return std::pow((A*B) / (A + B), Real(1) / K); | |
*/ | |
Real H = Clamp(Real(0.5) + Real(0.5)*(B - A) / K, 0, 1); | |
return Lerp(B, 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, | |
}; | |
} | |
Vec3 Repeat(const Vec3& Position, const Vec3& Bounds) | |
{ | |
return (Position % Bounds) - (Bounds*Real(0.5)); | |
} | |
Vec3 RepeatGround(const Vec3& Position, const Vec3& Bounds) | |
{ | |
Vec3 Rep{ Position }; | |
Rep.X = std::remainder(Rep.X, Bounds.X) - (Bounds.X * Real(0.5)); | |
Rep.Z = std::remainder(Rep.Z, Bounds.Z) - (Bounds.Z * Real(0.5)); | |
return Rep; | |
} | |
} | |
#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::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::SmoothUnion( | |
Distance, | |
Shapes::Torus( | |
Translate::RotX(Point - Vec3{ 0,Real(0.5),12 }, 45), | |
Real(0.5), Real(7) | |
), 3 | |
); | |
for( size_t i = 1; i < 5; i++ ) | |
{ | |
Distance = Operations::SmoothUnion( | |
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) | |
), 3); | |
} | |
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&#%@"; | |
int main() | |
{ | |
Vec3 LightDir = Vec3{ 1,1,1 }.Normalized(); | |
Vec3 EyePos = Vec3{ 0,2,-6 }; | |
std::string Screen; | |
Screen.reserve(WIDTH * HEIGHT); | |
do | |
{ | |
EyePos.Z += Real(0.25); | |
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 | |
15deg bisec = tan((pi/12)/2) = 30 degrees fov = 0.1316524975873958 | |
30deg bisec = tan((pi/6)/2) = 60 degrees fov = 0.26794919243112270 | |
36deg bisec = tan(((2pi)/5)/2) = 72 degrees fov = 0.7265425280053608858 | |
45dec bisec = tan((pi/2)/2) = 90 degrees fov = 1 | |
*/ | |
UV.Z = Real(1 / 0.7265425280053608858); | |
UV = UV.Normalized(); | |
bool Hit = false; | |
Real Distance = March(EyePos, UV, &Hit); | |
Vec3 Point = EyePos + (UV * 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); | |
Screen += Shades[static_cast<size_t>(Diffuse*(sizeof(Shades) - 2))]; | |
} | |
else | |
{ | |
Screen += ' '; | |
} | |
} | |
Screen += "\n"; | |
} | |
printf("%s", Screen.c_str()); | |
#ifdef _WIN32 | |
//CaptureScreen(GetForegroundWindow(), (std::to_string(Tick) + ".bmp").c_str()); | |
#endif | |
Screen.clear(); | |
} while( Tick < 300 ); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment