|
|
|
#define OLC_PGE_APPLICATION
|
|
|
|
#include "pixelGameEngine.h"
|
|
|
|
|
|
|
|
using namespace olc;
|
|
|
|
|
|
|
|
|
|
|
|
struct vec3d
|
|
|
|
{
|
|
|
|
float x, y, z;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct triangle
|
|
|
|
{
|
|
|
|
vec3d p[3];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct mesh
|
|
|
|
{
|
|
|
|
std::vector<triangle> tris;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct mat4x4
|
|
|
|
{
|
|
|
|
float m[4][4] = { 0 };
|
|
|
|
};
|
|
|
|
|
|
|
|
class olcEngine3D : public PixelGameEngine
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
olcEngine3D()
|
|
|
|
{
|
|
|
|
sAppName = "3D Demo";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
mesh meshCube;
|
|
|
|
mat4x4 matProj;
|
|
|
|
|
|
|
|
vec3d vCamera={0,0,0};
|
|
|
|
|
|
|
|
float fTheta=0;
|
|
|
|
|
|
|
|
void MultiplyMatrixVector(vec3d &i, vec3d &o, mat4x4 &m)
|
|
|
|
{
|
|
|
|
o.x = i.x * m.m[0][0] + i.y * m.m[1][0] + i.z * m.m[2][0] + m.m[3][0];
|
|
|
|
o.y = i.x * m.m[0][1] + i.y * m.m[1][1] + i.z * m.m[2][1] + m.m[3][1];
|
|
|
|
o.z = i.x * m.m[0][2] + i.y * m.m[1][2] + i.z * m.m[2][2] + m.m[3][2];
|
|
|
|
float w = i.x * m.m[0][3] + i.y * m.m[1][3] + i.z * m.m[2][3] + m.m[3][3];
|
|
|
|
|
|
|
|
if (w != 0.0f)
|
|
|
|
{
|
|
|
|
o.x /= w; o.y /= w; o.z /= w;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
bool OnUserCreate() override
|
|
|
|
{
|
|
|
|
meshCube.tris = {
|
|
|
|
|
|
|
|
// SOUTH
|
|
|
|
{ 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f },
|
|
|
|
{ 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f },
|
|
|
|
|
|
|
|
// EAST
|
|
|
|
{ 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f },
|
|
|
|
{ 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f },
|
|
|
|
|
|
|
|
// NORTH
|
|
|
|
{ 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f },
|
|
|
|
{ 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f },
|
|
|
|
|
|
|
|
// WEST
|
|
|
|
{ 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f },
|
|
|
|
{ 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f },
|
|
|
|
|
|
|
|
// TOP
|
|
|
|
{ 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f },
|
|
|
|
{ 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f },
|
|
|
|
|
|
|
|
// BOTTOM
|
|
|
|
{ 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f },
|
|
|
|
{ 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f },
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
// Projection Matrix
|
|
|
|
float fNear = 0.1f;
|
|
|
|
float fFar = 1000.0f;
|
|
|
|
float fFov = 90.0f;
|
|
|
|
float fAspectRatio = (float)ScreenHeight() / (float)ScreenWidth();
|
|
|
|
float fFovRad = 1.0f / tanf(fFov * 0.5f / 180.0f * 3.14159f);
|
|
|
|
|
|
|
|
matProj.m[0][0] = fAspectRatio * fFovRad;
|
|
|
|
matProj.m[1][1] = fFovRad;
|
|
|
|
matProj.m[2][2] = fFar / (fFar - fNear);
|
|
|
|
matProj.m[3][2] = (-fFar * fNear) / (fFar - fNear);
|
|
|
|
matProj.m[2][3] = 1.0f;
|
|
|
|
matProj.m[3][3] = 0.0f;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool OnUserUpdate(float fElapsedTime) override
|
|
|
|
{
|
|
|
|
// Set up rotation matrices
|
|
|
|
mat4x4 matRotZ, matRotX;
|
|
|
|
fTheta += 1.0f * fElapsedTime;
|
|
|
|
|
|
|
|
// Rotation Z
|
|
|
|
matRotZ.m[0][0] = cosf(fTheta);
|
|
|
|
matRotZ.m[0][1] = sinf(fTheta);
|
|
|
|
matRotZ.m[1][0] = -sinf(fTheta);
|
|
|
|
matRotZ.m[1][1] = cosf(fTheta);
|
|
|
|
matRotZ.m[2][2] = 1;
|
|
|
|
matRotZ.m[3][3] = 1;
|
|
|
|
|
|
|
|
// Rotation X
|
|
|
|
matRotX.m[0][0] = 1;
|
|
|
|
matRotX.m[1][1] = cosf(fTheta * 0.5f);
|
|
|
|
matRotX.m[1][2] = sinf(fTheta * 0.5f);
|
|
|
|
matRotX.m[2][1] = -sinf(fTheta * 0.5f);
|
|
|
|
matRotX.m[2][2] = cosf(fTheta * 0.5f);
|
|
|
|
matRotX.m[3][3] = 1;
|
|
|
|
|
|
|
|
// Draw Triangles
|
|
|
|
for (auto&tri : meshCube.tris)
|
|
|
|
{
|
|
|
|
triangle triProjected, triTranslated, triRotatedZ, triRotatedZX;
|
|
|
|
|
|
|
|
// Rotate in Z-Axis
|
|
|
|
MultiplyMatrixVector(tri.p[0], triRotatedZ.p[0], matRotZ);
|
|
|
|
MultiplyMatrixVector(tri.p[1], triRotatedZ.p[1], matRotZ);
|
|
|
|
MultiplyMatrixVector(tri.p[2], triRotatedZ.p[2], matRotZ);
|
|
|
|
|
|
|
|
// Rotate in X-Axis
|
|
|
|
MultiplyMatrixVector(triRotatedZ.p[0], triRotatedZX.p[0], matRotX);
|
|
|
|
MultiplyMatrixVector(triRotatedZ.p[1], triRotatedZX.p[1], matRotX);
|
|
|
|
MultiplyMatrixVector(triRotatedZ.p[2], triRotatedZX.p[2], matRotX);
|
|
|
|
|
|
|
|
// Offset into the screen
|
|
|
|
triTranslated = triRotatedZX;
|
|
|
|
triTranslated.p[0].z = triRotatedZX.p[0].z + 3.0f;
|
|
|
|
triTranslated.p[1].z = triRotatedZX.p[1].z + 3.0f;
|
|
|
|
triTranslated.p[2].z = triRotatedZX.p[2].z + 3.0f;
|
|
|
|
|
|
|
|
vec3d normal,line1,line2;
|
|
|
|
line1.x=triTranslated.p[1].x-triTranslated.p[0].x;
|
|
|
|
line1.y=triTranslated.p[1].y-triTranslated.p[0].y;
|
|
|
|
line1.z=triTranslated.p[1].z-triTranslated.p[0].z;
|
|
|
|
line2.x=triTranslated.p[2].x-triTranslated.p[0].x;
|
|
|
|
line2.y=triTranslated.p[2].y-triTranslated.p[0].y;
|
|
|
|
line2.z=triTranslated.p[2].z-triTranslated.p[0].z;
|
|
|
|
|
|
|
|
normal.x=line1.y*line2.z-line1.z*line2.y;
|
|
|
|
normal.y=line1.z*line2.x-line1.x*line2.z;
|
|
|
|
normal.z=line1.x*line2.y-line1.y*line2.x;
|
|
|
|
|
|
|
|
float l = sqrtf(normal.x*normal.x+normal.y*normal.y+normal.z*normal.z);
|
|
|
|
normal.x/=l;normal.y/=l;normal.z/=l;
|
|
|
|
|
|
|
|
if (normal.x*(triTranslated.p[0].x-vCamera.x)+
|
|
|
|
normal.y*(triTranslated.p[0].y-vCamera.y)+
|
|
|
|
normal.z*(triTranslated.p[0].z-vCamera.z)<0) {
|
|
|
|
|
|
|
|
vec3d light_dir = {0,0,-1};
|
|
|
|
float l = sqrtf(light_dir.x*light_dir.x+light_dir.y*light_dir.y+light_dir.z*light_dir.z);
|
|
|
|
light_dir.x/=l;light_dir.y/=l;light_dir.z/=l;
|
|
|
|
|
|
|
|
float dp = normal.x*(light_dir.x-vCamera.x)+
|
|
|
|
normal.y*(light_dir.y-vCamera.y)+
|
|
|
|
normal.z*(light_dir.z-vCamera.z);
|
|
|
|
|
|
|
|
|
|
|
|
// Project triangles from 3D --> 2D
|
|
|
|
MultiplyMatrixVector(triTranslated.p[0], triProjected.p[0], matProj);
|
|
|
|
MultiplyMatrixVector(triTranslated.p[1], triProjected.p[1], matProj);
|
|
|
|
MultiplyMatrixVector(triTranslated.p[2], triProjected.p[2], matProj);
|
|
|
|
|
|
|
|
// Scale into view
|
|
|
|
triProjected.p[0].x += 1.0f; triProjected.p[0].y += 1.0f;
|
|
|
|
triProjected.p[1].x += 1.0f; triProjected.p[1].y += 1.0f;
|
|
|
|
triProjected.p[2].x += 1.0f; triProjected.p[2].y += 1.0f;
|
|
|
|
triProjected.p[0].x *= 0.5f * (float)ScreenWidth();
|
|
|
|
triProjected.p[0].y *= 0.5f * (float)ScreenHeight();
|
|
|
|
triProjected.p[1].x *= 0.5f * (float)ScreenWidth();
|
|
|
|
triProjected.p[1].y *= 0.5f * (float)ScreenHeight();
|
|
|
|
triProjected.p[2].x *= 0.5f * (float)ScreenWidth();
|
|
|
|
triProjected.p[2].y *= 0.5f * (float)ScreenHeight();
|
|
|
|
|
|
|
|
// Rasterize triangle
|
|
|
|
//SetDecalMode(DecalMode::WIREFRAME);
|
|
|
|
DrawPolygonDecal(nullptr,{
|
|
|
|
{triProjected.p[0].x, triProjected.p[0].y},
|
|
|
|
{triProjected.p[1].x, triProjected.p[1].y},
|
|
|
|
{triProjected.p[2].x, triProjected.p[2].y}
|
|
|
|
},{
|
|
|
|
{0,0},
|
|
|
|
{0,0},
|
|
|
|
{0,0},
|
|
|
|
},Pixel(255*dp*dp,255*dp*dp,255*dp*dp));
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main()
|
|
|
|
{
|
|
|
|
olcEngine3D demo;
|
|
|
|
if (demo.Construct(1280, 720, 1, 1))
|
|
|
|
demo.Start();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|