feat: display a handheld item in first-person view (WIP)

This commit is contained in:
MihailRis 2024-10-27 17:07:32 +03:00
parent fb17228eff
commit b93668ba94
9 changed files with 110 additions and 38 deletions

View File

@ -101,7 +101,7 @@ void LevelScreen::saveWorldPreview() {
Viewport viewport(previewSize * 1.5, previewSize);
DrawContext ctx(&pctx, viewport, batch.get());
worldRenderer->draw(ctx, &camera, false, true, 0.0f, postProcessing.get());
worldRenderer->draw(ctx, camera, false, true, 0.0f, postProcessing.get());
auto image = postProcessing->toImage();
image->flipY();
imageio::write(paths->resolve("world:preview.png").u8string(), image.get());
@ -164,7 +164,9 @@ void LevelScreen::draw(float delta) {
Viewport viewport(Window::width, Window::height);
DrawContext ctx(nullptr, viewport, batch.get());
worldRenderer->draw(ctx, camera.get(), hudVisible, hud->isPause(), delta, postProcessing.get());
worldRenderer->draw(
ctx, *camera, hudVisible, hud->isPause(), delta, postProcessing.get()
);
if (hudVisible) {
hud->draw(ctx);

View File

@ -77,6 +77,7 @@ void ModelBatch::draw(const model::Mesh& mesh, const glm::mat4& matrix,
const texture_names_map* varTextures,
bool backlight) {
glm::vec3 gpos = matrix * glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
gpos += lightsOffset;
light_t light = chunks->getLight(
std::floor(gpos.x),
std::floor(std::min(CHUNK_H-1.0f, gpos.y)),
@ -137,6 +138,10 @@ void ModelBatch::render() {
entries.clear();
}
void ModelBatch::setLightsOffset(const glm::vec3& offset) {
lightsOffset = offset;
}
void ModelBatch::setTexture(const std::string& name,
const texture_names_map* varTextures) {
if (name.at(0) == '$') {

View File

@ -34,6 +34,7 @@ class ModelBatch {
Texture* texture = nullptr;
UVRegion region {0.0f, 0.0f, 1.0f, 1.0f};
const EngineSettings* settings;
glm::vec3 lightsOffset {};
static inline glm::vec3 SUN_VECTOR {0.411934f, 0.863868f, -0.279161f};
@ -96,4 +97,6 @@ public:
const model::Model* model,
const texture_names_map* varTextures);
void render();
void setLightsOffset(const glm::vec3& offset);
};

View File

@ -78,17 +78,17 @@ WorldRenderer::WorldRenderer(
WorldRenderer::~WorldRenderer() = default;
bool WorldRenderer::drawChunk(
size_t index, Camera* camera, Shader* shader, bool culling
size_t index, const Camera& camera, Shader* shader, bool culling
) {
auto chunk = level->chunks->getChunks()[index];
if (!chunk->flags.lighted) {
return false;
}
float distance = glm::distance(
camera->position,
camera.position,
glm::vec3(
(chunk->x + 0.5f) * CHUNK_W,
camera->position.y,
camera.position.y,
(chunk->z + 0.5f) * CHUNK_D
)
);
@ -113,7 +113,9 @@ bool WorldRenderer::drawChunk(
return true;
}
void WorldRenderer::drawChunks(Chunks* chunks, Camera* camera, Shader* shader) {
void WorldRenderer::drawChunks(
Chunks* chunks, const Camera& camera, Shader* shader
) {
auto assets = engine->getAssets();
auto atlas = assets->get<Atlas>("blocks");
@ -127,8 +129,8 @@ void WorldRenderer::drawChunks(Chunks* chunks, Camera* camera, Shader* shader) {
if (chunks->getChunks()[i] == nullptr) continue;
indices.emplace_back(i);
}
float px = camera->position.x / static_cast<float>(CHUNK_W) - 0.5f;
float pz = camera->position.z / static_cast<float>(CHUNK_D) - 0.5f;
float px = camera.position.x / static_cast<float>(CHUNK_W) - 0.5f;
float pz = camera.position.z / static_cast<float>(CHUNK_D) - 0.5f;
std::sort(indices.begin(), indices.end(), [chunks, px, pz](auto i, auto j) {
const auto& chunksBuffer = chunks->getChunks();
const auto a = chunksBuffer[i].get();
@ -141,7 +143,7 @@ void WorldRenderer::drawChunks(Chunks* chunks, Camera* camera, Shader* shader) {
});
bool culling = engine->getSettings().graphics.frustumCulling.get();
if (culling) {
frustumCulling->update(camera->getProjView());
frustumCulling->update(camera.getProjView());
}
chunks->visible = 0;
for (size_t i = 0; i < indices.size(); i++) {
@ -151,20 +153,20 @@ void WorldRenderer::drawChunks(Chunks* chunks, Camera* camera, Shader* shader) {
void WorldRenderer::setupWorldShader(
Shader* shader,
Camera* camera,
const Camera& camera,
const EngineSettings& settings,
float fogFactor
) {
shader->use();
shader->uniformMatrix("u_model", glm::mat4(1.0f));
shader->uniformMatrix("u_proj", camera->getProjection());
shader->uniformMatrix("u_view", camera->getView());
shader->uniformMatrix("u_proj", camera.getProjection());
shader->uniformMatrix("u_view", camera.getView());
shader->uniform1f("u_timer", timer);
shader->uniform1f("u_gamma", settings.graphics.gamma.get());
shader->uniform1f("u_fogFactor", fogFactor);
shader->uniform1f("u_fogCurve", settings.graphics.fogCurve.get());
shader->uniform1f("u_dayTime", level->getWorld()->getInfo().daytime);
shader->uniform3f("u_cameraPos", camera->position);
shader->uniform3f("u_cameraPos", camera.position);
shader->uniform1i("u_cubemap", 1);
auto indices = level->content->getIndices();
@ -186,7 +188,7 @@ void WorldRenderer::setupWorldShader(
void WorldRenderer::renderLevel(
const DrawContext&,
Camera* camera,
const Camera& camera,
const EngineSettings& settings,
float delta,
bool pause
@ -251,10 +253,10 @@ void WorldRenderer::renderBlockSelection() {
}
void WorldRenderer::renderLines(
Camera* camera, Shader* linesShader, const DrawContext& pctx
const Camera& camera, Shader* linesShader, const DrawContext& pctx
) {
linesShader->use();
linesShader->uniformMatrix("u_projview", camera->getProjView());
linesShader->uniformMatrix("u_projview", camera.getProjView());
if (player->selection.vox.id != BLOCK_VOID) {
renderBlockSelection();
}
@ -268,7 +270,7 @@ void WorldRenderer::renderLines(
}
void WorldRenderer::renderDebugLines(
const DrawContext& pctx, Camera* camera, Shader* linesShader
const DrawContext& pctx, const Camera& camera, Shader* linesShader
) {
DrawContext ctx = pctx.sub(lineBatch.get());
const auto& viewport = ctx.getViewport();
@ -280,7 +282,7 @@ void WorldRenderer::renderDebugLines(
linesShader->use();
if (showChunkBorders) {
linesShader->uniformMatrix("u_projview", camera->getProjView());
linesShader->uniformMatrix("u_projview", camera.getProjView());
glm::vec3 coord = player->camera->position;
if (coord.x < 0) coord.x--;
if (coord.z < 0) coord.z--;
@ -310,7 +312,7 @@ void WorldRenderer::renderDebugLines(
-length,
length
) * model *
glm::inverse(camera->rotation)
glm::inverse(camera.rotation)
);
ctx.setDepthTest(false);
@ -327,9 +329,61 @@ void WorldRenderer::renderDebugLines(
lineBatch->line(0.f, 0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 1.f);
}
void WorldRenderer::renderHands(const Camera& camera, const Assets& assets) {
auto entityShader = assets.get<Shader>("entity");
auto indices = level->content->getIndices();
// get current chosen item
const auto& inventory = player->getInventory();
int slot = player->getChosenSlot();
const ItemStack& stack = inventory->getSlot(slot);
const auto& def = indices->items.require(stack.getItemId());
// prepare modified HUD camera
Camera hudcam = camera;
hudcam.far = 100.0f;
hudcam.setFov(1.2f);
hudcam.position = {};
// configure model matrix
const glm::vec3 itemOffset(0.08f, 0.035f, -0.1);
glm::mat4 matrix = glm::translate(glm::mat4(1.0f), itemOffset);
matrix = glm::scale(matrix, glm::vec3(0.1f));
matrix = camera.rotation * matrix *
glm::rotate(
glm::mat4(1.0f), -glm::pi<float>() * 0.5f, glm::vec3(0, 1, 0)
);
auto offset = -(camera.position - player->getPosition());
float angle = glm::radians(player->cam.x - 90);
float cos = glm::cos(angle);
float sin = glm::sin(angle);
float newX = offset.x * cos - offset.z * sin;
float newZ = offset.x * sin + offset.z * cos;
matrix = matrix *
glm::translate(glm::mat4(1.0f), glm::vec3(newX, offset.y, newZ));
// render
texture_names_map map = {};
modelBatch->setLightsOffset(camera.position);
modelBatch->draw(
matrix,
glm::vec3(1.0f),
assets.get<model::Model>(def.name + ".model"),
&map
);
Window::clearDepth();
setupWorldShader(entityShader, hudcam, engine->getSettings(), 0.0f);
skybox->bind();
modelBatch->render();
modelBatch->setLightsOffset(glm::vec3());
skybox->unbind();
}
void WorldRenderer::draw(
const DrawContext& pctx,
Camera* camera,
Camera& camera,
bool hudVisible,
bool pause,
float delta,
@ -338,7 +392,7 @@ void WorldRenderer::draw(
timer += delta * !pause;
auto world = level->getWorld();
const Viewport& vp = pctx.getViewport();
camera->aspect = vp.getWidth() / static_cast<float>(vp.getHeight());
camera.aspect = vp.getWidth() / static_cast<float>(vp.getHeight());
const auto& settings = engine->getSettings();
const auto& worldInfo = world->getInfo();
@ -356,7 +410,7 @@ void WorldRenderer::draw(
Window::clearDepth();
// Drawing background sky plane
skybox->draw(pctx, camera, assets, worldInfo.daytime, worldInfo.fog);
skybox->draw(pctx, &camera, assets, worldInfo.daytime, worldInfo.fog);
// Actually world render with depth buffer on
{
@ -367,6 +421,7 @@ void WorldRenderer::draw(
// Debug lines
if (hudVisible) {
renderLines(camera, linesShader, ctx);
renderHands(camera, *assets);
}
}

View File

@ -23,6 +23,7 @@ class Skybox;
class PostProcessing;
class DrawContext;
class ModelBatch;
class Assets;
struct EngineSettings;
namespace model {
@ -41,16 +42,20 @@ class WorldRenderer {
std::unique_ptr<ModelBatch> modelBatch;
float timer = 0.0f;
bool drawChunk(size_t index, Camera* camera, Shader* shader, bool culling);
void drawChunks(Chunks* chunks, Camera* camera, Shader* shader);
bool drawChunk(size_t index, const Camera& camera, Shader* shader, bool culling);
void drawChunks(Chunks* chunks, const Camera& camera, Shader* shader);
/// @brief Render block selection lines
void renderBlockSelection();
void renderHands(const Camera& camera, const Assets& assets);
/// @brief Render lines (selection and debug)
/// @param camera active camera
/// @param linesShader shader used
void renderLines(Camera* camera, Shader* linesShader, const DrawContext& pctx);
void renderLines(
const Camera& camera, Shader* linesShader, const DrawContext& pctx
);
/// @brief Render all debug lines (chunks borders, coord system guides)
/// @param context graphics context
@ -58,13 +63,13 @@ class WorldRenderer {
/// @param linesShader shader used
void renderDebugLines(
const DrawContext& context,
Camera* camera,
const Camera& camera,
Shader* linesShader
);
void setupWorldShader(
Shader* shader,
Camera* camera,
const Camera& camera,
const EngineSettings& settings,
float fogFactor
);
@ -77,7 +82,7 @@ public:
void draw(
const DrawContext& context,
Camera* camera,
Camera& camera,
bool hudVisible,
bool pause,
float delta,
@ -91,7 +96,7 @@ public:
/// @param settings engine settings
void renderLevel(
const DrawContext& context,
Camera* camera,
const Camera& camera,
const EngineSettings& settings,
float delta,
bool pause

View File

@ -252,7 +252,7 @@ entityid_t Player::getSelectedEntity() const {
return selectedEid;
}
std::shared_ptr<Inventory> Player::getInventory() const {
const std::shared_ptr<Inventory>& Player::getInventory() const {
return inventory;
}

View File

@ -91,7 +91,7 @@ public:
entityid_t getSelectedEntity() const;
std::shared_ptr<Inventory> getInventory() const;
const std::shared_ptr<Inventory>& getInventory() const;
glm::vec3 getPosition() const {
return position;

View File

@ -29,21 +29,21 @@ void Camera::rotate(float x, float y, float z) {
updateVectors();
}
glm::mat4 Camera::getProjection() {
glm::mat4 Camera::getProjection() const {
constexpr float epsilon = 1e-6f; // 0.000001
float aspect_ratio = this->aspect;
if (std::fabs(aspect_ratio) < epsilon) {
aspect_ratio = (float)Window::width / (float)Window::height;
}
if (perspective)
return glm::perspective(fov * zoom, aspect_ratio, 0.05f, 1500.0f);
return glm::perspective(fov * zoom, aspect_ratio, near, far);
else if (flipped)
return glm::ortho(0.0f, fov * aspect_ratio, fov, 0.0f);
else
return glm::ortho(0.0f, fov * aspect_ratio, 0.0f, fov);
}
glm::mat4 Camera::getView(bool pos) {
glm::mat4 Camera::getView(bool pos) const {
glm::vec3 camera_pos = this->position;
if (!pos) {
camera_pos = glm::vec3(0.0f);
@ -55,7 +55,7 @@ glm::mat4 Camera::getView(bool pos) {
}
}
glm::mat4 Camera::getProjView(bool pos) {
glm::mat4 Camera::getProjView(bool pos) const {
return getProjection() * getView(pos);
}

View File

@ -18,6 +18,8 @@ public:
bool perspective = true;
bool flipped = false;
float aspect = 0.0f;
float near = 0.05f;
float far = 1500.0f;
Camera() {
updateVectors();
@ -27,9 +29,9 @@ public:
void updateVectors();
void rotate(float x, float y, float z);
glm::mat4 getProjection();
glm::mat4 getView(bool position = true);
glm::mat4 getProjView(bool position = true);
glm::mat4 getProjection() const;
glm::mat4 getView(bool position = true) const;
glm::mat4 getProjView(bool position = true) const;
void setFov(float fov);
float getFov() const;