Render a simple 3D box.

This commit is contained in:
Attila Uygun 2021-10-27 21:55:46 +02:00
parent 1e57355593
commit 3779e78675
11 changed files with 245 additions and 47 deletions

View File

@ -1,33 +1 @@
A simple, cross-platform 2D game engine with OpenGL and Vulkan renderers. 3D rendering test branch. Check master branch for more info about the project.
Supports Linux and Android (lolipop+) platforms.
This is a personal hobby project. I've published a little game on
[Google Play](https://play.google.com/store/apps/details?id=com.woom.game)
based on this engine. Full game code and assets are included in this repository.
#### Building the demo
Linux:
```text
cd build/linux
make
```
Android:
```text
cd build/android
./gradlew :app:assembleRelease
```
GN (linux only for now):
```text
gn gen --args='is_debug=false' out/release
ninja -C out/release
```
#### Third-party libraries:
[glew](https://github.com/nigels-com/glew),
[jsoncpp](https://github.com/open-source-parsers/jsoncpp),
[minimp3](https://github.com/lieff/minimp3),
[oboe](https://github.com/google/oboe),
[stb](https://github.com/nothings/stb),
[texture-compressor](https://github.com/auygun/kaliber/tree/master/src/third_party/texture_compressor),
[minizip](https://github.com/madler/zlib/tree/master/contrib/minizip),
[glslang](https://github.com/KhronosGroup/glslang),
[spirv-reflect](https://github.com/KhronosGroup/SPIRV-Reflect),
[vma](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator),
[vulkan-sdk](https://vulkan.lunarg.com)

View File

@ -0,0 +1,15 @@
#ifdef GL_ES
precision mediump float;
#endif
IN(0) vec3 color;
UNIFORM_BEGIN
UNIFORM_V(mat4 projection)
UNIFORM_END
FRAG_COLOR_OUT(frag_color)
void main() {
FRAG_COLOR(frag_color) = vec4(color, 1.0);
}

View File

@ -0,0 +1,13 @@
IN(0) vec3 in_position;
IN(1) vec3 in_color;
UNIFORM_BEGIN
UNIFORM_V(mat4 mvp)
UNIFORM_END
OUT(0) vec3 color;
void main() {
color = in_color;
gl_Position = PARAM(mvp) * vec4(in_position, 1.0);
}

View File

@ -55,13 +55,8 @@ add_library(kaliber SHARED
../../../src/base/task_runner.cc ../../../src/base/task_runner.cc
../../../src/base/thread_pool.cc ../../../src/base/thread_pool.cc
../../../src/base/timer.cc ../../../src/base/timer.cc
../../../src/demo/credits.cc ../../../src/k3dtest/k3dtest.cc
../../../src/demo/demo.cc ../../../src/k3dtest/model.cc
../../../src/demo/enemy.cc
../../../src/demo/hud.cc
../../../src/demo/menu.cc
../../../src/demo/player.cc
../../../src/demo/sky_quad.cc
../../../src/engine/animatable.cc ../../../src/engine/animatable.cc
../../../src/engine/animator.cc ../../../src/engine/animator.cc
../../../src/engine/audio/audio_base.cc ../../../src/engine/audio/audio_base.cc

View File

@ -186,13 +186,8 @@ $(ENGINE_LIB): $(ENGINE_OBJS)
ifneq ($(filter demo,$(APPS)),) ifneq ($(filter demo,$(APPS)),)
DEMO_SRC := \ DEMO_SRC := \
$(SRC_ROOT)/demo/credits.cc \ $(SRC_ROOT)/k3dtest/k3dtest.cc \
$(SRC_ROOT)/demo/demo.cc \ $(SRC_ROOT)/k3dtest/model.cc
$(SRC_ROOT)/demo/enemy.cc \
$(SRC_ROOT)/demo/hud.cc \
$(SRC_ROOT)/demo/menu.cc \
$(SRC_ROOT)/demo/player.cc \
$(SRC_ROOT)/demo/sky_quad.cc
DEMO_EXE := $(call app_exe,demo) DEMO_EXE := $(call app_exe,demo)
DEMO_OBJS := $(call objs_from_src, $(DEMO_SRC)) DEMO_OBJS := $(call objs_from_src, $(DEMO_SRC))

View File

@ -36,6 +36,8 @@ Engine::Engine(Platform* platform, Renderer* renderer, Audio* audio)
pass_through_shader_ = CreateRenderResource<Shader>(); pass_through_shader_ = CreateRenderResource<Shader>();
solid_shader_ = CreateRenderResource<Shader>(); solid_shader_ = CreateRenderResource<Shader>();
box_shader_ = CreateRenderResource<Shader>();
stats_ = std::make_unique<ImageQuad>(); stats_ = std::make_unique<ImageQuad>();
} }
@ -62,6 +64,9 @@ bool Engine::Initialize() {
projection_.CreateOrthoProjection(-1.0, 1.0, -aspect_ratio, aspect_ratio); projection_.CreateOrthoProjection(-1.0, 1.0, -aspect_ratio, aspect_ratio);
} }
fov_projection_.CreateFovProjection(45, 4.0f / 3.0f, (float)GetScreenWidth(),
(float)GetScreenHeight(), 4, 2048);
LOG << "image scale factor: " << GetImageScaleFactor(); LOG << "image scale factor: " << GetImageScaleFactor();
if (renderer_->SupportsDXT5()) { if (renderer_->SupportsDXT5()) {
@ -493,6 +498,15 @@ bool Engine::CreateRenderResources() {
solid_shader_->Create(std::move(source), quad_->vertex_description(), solid_shader_->Create(std::move(source), quad_->vertex_description(),
quad_->primitive(), false); quad_->primitive(), false);
VertexDescripton vd_3d;
ParseVertexDescription("p3f;c3f", vd_3d);
source = std::make_unique<ShaderSource>();
if (!source->Load("engine/3d.glsl")) {
LOG << "Could not create 3d shader.";
return false;
}
box_shader_->Create(std::move(source), vd_3d, kPrimitive_Triangles, true);
return true; return true;
} }

View File

@ -108,6 +108,7 @@ class Engine {
Geometry* GetQuad() { return quad_.get(); } Geometry* GetQuad() { return quad_.get(); }
Shader* GetPassThroughShader() { return pass_through_shader_.get(); } Shader* GetPassThroughShader() { return pass_through_shader_.get(); }
Shader* GetSolidShader() { return solid_shader_.get(); } Shader* GetSolidShader() { return solid_shader_.get(); }
Shader* GetBoxShader() { return box_shader_.get(); }
const Font* GetSystemFont() { return system_font_.get(); } const Font* GetSystemFont() { return system_font_.get(); }
@ -125,6 +126,9 @@ class Engine {
base::Vector2f GetScreenSize() const { return screen_size_; } base::Vector2f GetScreenSize() const { return screen_size_; }
const base::Matrix4f& GetProjectionMatrix() const { return projection_; } const base::Matrix4f& GetProjectionMatrix() const { return projection_; }
const base::Matrix4f& GetFovProjectionMatrix() const {
return fov_projection_;
}
int GetDeviceDpi() const; int GetDeviceDpi() const;
@ -172,8 +176,11 @@ class Engine {
std::unique_ptr<Shader> pass_through_shader_; std::unique_ptr<Shader> pass_through_shader_;
std::unique_ptr<Shader> solid_shader_; std::unique_ptr<Shader> solid_shader_;
std::unique_ptr<Shader> box_shader_;
base::Vector2f screen_size_ = {0, 0}; base::Vector2f screen_size_ = {0, 0};
base::Matrix4f projection_; base::Matrix4f projection_;
base::Matrix4f fov_projection_;
std::unique_ptr<Font> system_font_; std::unique_ptr<Font> system_font_;

48
src/k3dtest/k3dtest.cc Normal file
View File

@ -0,0 +1,48 @@
#include "k3dtest.h"
#include <algorithm>
#include <atomic>
#include <iostream>
#include <string>
#include "../base/file.h"
#include "../base/interpolation.h"
#include "../base/log.h"
#include "../base/random.h"
#include "../base/timer.h"
#include "../engine/engine.h"
#include "../engine/game_factory.h"
#include "../engine/input_event.h"
#include "../engine/sound.h"
DECLARE_GAME_BEGIN
DECLARE_GAME(K3dTest)
DECLARE_GAME_END
using namespace std::string_literals;
using namespace base;
using namespace eng;
K3dTest::K3dTest() = default;
K3dTest::~K3dTest() = default;
bool K3dTest::Initialize() {
box_.Create();
box_.SetVisible(true);
return true;
}
void K3dTest::Update(float delta_time) {
box_.Update();
}
void K3dTest::ContextLost() {
}
void K3dTest::LostFocus() {}
void K3dTest::GainedFocus(bool from_interstitial_ad) {
}

32
src/k3dtest/k3dtest.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef K3DTEST_H
#define K3DTEST_H
#include "../base/closure.h"
#include "../engine/animator.h"
#include "../engine/font.h"
#include "../engine/game.h"
#include "../engine/persistent_data.h"
#include "../engine/solid_quad.h"
#include "../engine/sound_player.h"
#include "model.h"
class K3dTest : public eng::Game {
public:
K3dTest();
~K3dTest() override;
bool Initialize() override;
void Update(float delta_time) override;
void ContextLost() override;
void LostFocus() override;
void GainedFocus(bool from_interstitial_ad) override;
private:
Model box_;
};
#endif // K3DTEST_H

75
src/k3dtest/model.cc Normal file
View File

@ -0,0 +1,75 @@
#include "model.h"
#include "../base/interpolation.h"
#include "../base/log.h"
#include "../base/random.h"
#include "../engine/engine.h"
#include "../engine/mesh.h"
#include "../engine/renderer/geometry.h"
#include "../engine/renderer/shader.h"
using namespace base;
using namespace eng;
Model::Model() : model_(Engine::Get().CreateRenderResource<Geometry>()) {}
Model::~Model() = default;
bool Model::Create() {
static const char box_vertex_description[] = "p3f;c3f";
static const float box_vertices[] = {
// front
-1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
// back
-1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 1.0f,
0.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
1.0f};
static const unsigned short box_indices[] = {// front
0, 1, 2, 2, 3, 0,
// right
1, 5, 6, 6, 2, 1,
// back
7, 6, 5, 5, 4, 7,
// left
4, 0, 3, 3, 7, 4,
// bottom
4, 5, 1, 1, 0, 4,
// top
3, 2, 6, 6, 7, 3};
auto box_mesh = std::make_unique<Mesh>();
box_mesh->Create(kPrimitive_Triangles, box_vertex_description, 8,
box_vertices, kDataType_UShort, 12 * 3, box_indices);
model_->Create(std::move(box_mesh));
return true;
}
void Model::Draw(float frame_frac) {
DCHECK(IsVisible());
float tick_time = Engine::Get().time_step() * 0.2;
float ang = ticks_ * tick_time + tick_time * frame_frac;
Matrix4f model;
model.CreateFromAngles({0, std::fmod(ang, 1.0f), 0}, 1);
model.GetRow(3) = Vector3f(0, 0, 0);
Matrix4f view, inv_view;
view.CreateLookAt({10, -5, 10}, {0, 0, 0});
view.InverseOrthogonal(inv_view);
Matrix4f model_view, mvp;
model.Multiply(inv_view, model_view);
model_view.Multiply(Engine::Get().GetFovProjectionMatrix(), mvp);
Engine::Get().GetBoxShader()->Activate();
Engine::Get().GetBoxShader()->SetUniform("mvp", mvp);
Engine::Get().GetBoxShader()->UploadUniforms();
model_->Draw();
}
void Model::Update() {
++ticks_;
}

36
src/k3dtest/model.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef MODEL_H
#define MODEL_H
#include "../base/vecmath.h"
#include "../engine/drawable.h"
#include <array>
#include <memory>
#include <string>
#include <vector>
namespace eng {
class Geometry;
} // namespace eng
class Model : public eng::Drawable {
public:
Model();
~Model();
bool Create();
// Drawable interface.
void Draw(float frame_frac) override;
void Update();
private:
std::unique_ptr<eng::Geometry> model_;
size_t ticks_ = 0;
Model(const Model&) = delete;
Model& operator=(const Model&) = delete;
};
#endif // MODEL_H