From e0b6da6c109d4c1f378ca19f45f73f31a2397808 Mon Sep 17 00:00:00 2001 From: Jukitsu <84381972+Jukitsu@users.noreply.github.com> Date: Mon, 5 Aug 2024 14:57:08 +0200 Subject: [PATCH] Kyoto update HAH look at this monke --- Jukcraft/assets/shaders/entity/frag.glsl | 9 ++- Jukcraft/assets/shaders/entity/vert.glsl | 8 ++- Jukcraft/src/core/Camera.cpp | 22 ++++--- Jukcraft/src/core/Camera.h | 2 + Jukcraft/src/core/Game.cpp | 12 +++- Jukcraft/src/entity/Entity.h | 4 +- Jukcraft/src/entity/LivingEntity.cpp | 49 +++++++++------ Jukcraft/src/entity/LivingEntity.h | 41 ++++++++++++- Jukcraft/src/entity/Mob.cpp | 50 ++++++++------- Jukcraft/src/entity/player/Player.cpp | 2 - Jukcraft/src/models/entity/EntityModel.cpp | 5 ++ Jukcraft/src/models/entity/EntityModel.h | 1 + .../renderer/entity/LivingEntityRenderer.cpp | 61 +++++++++++++------ Jukcraft/src/renderer/gfx/objects/Shader.h | 4 ++ 14 files changed, 191 insertions(+), 79 deletions(-) diff --git a/Jukcraft/assets/shaders/entity/frag.glsl b/Jukcraft/assets/shaders/entity/frag.glsl index e6c25e3..56d2d09 100644 --- a/Jukcraft/assets/shaders/entity/frag.glsl +++ b/Jukcraft/assets/shaders/entity/frag.glsl @@ -4,13 +4,18 @@ layout(early_fragment_tests) in; layout(location = 0) in VS_OUT { vec2 v_TexCoords; + float v_Shading; } fs_In; + +layout(location = 0) uniform vec4 u_Overlay; layout(binding = 1) uniform sampler2D u_TextureSampler; layout(location = 0) out vec4 fragColor; void main(void) { - vec4 texel = texture(u_TextureSampler, fs_In.v_TexCoords); - fragColor = texel; + vec4 color = texture(u_TextureSampler, fs_In.v_TexCoords); + color.rgb = mix(u_Overlay.rgb, color.rgb, u_Overlay.a); + color.rgb *= fs_In.v_Shading; + fragColor = color; } \ No newline at end of file diff --git a/Jukcraft/assets/shaders/entity/vert.glsl b/Jukcraft/assets/shaders/entity/vert.glsl index fefea25..5fc14ae 100644 --- a/Jukcraft/assets/shaders/entity/vert.glsl +++ b/Jukcraft/assets/shaders/entity/vert.glsl @@ -1,10 +1,12 @@ #version 460 core -layout(location = 0) in vec3 a_VertexPos; +layout(location = 0) in vec3 a_Pos; layout(location = 1) in vec2 a_TexUV; +layout(location = 2) in vec3 a_Normal; layout(location = 0) out VS_OUT { vec2 v_TexCoords; + float v_Shading; } vs_Out; layout(std140, binding = 0) uniform u_Camera { @@ -12,8 +14,10 @@ layout(std140, binding = 0) uniform u_Camera { vec4 u_CameraPos; }; +const vec3 c_Sunlight = normalize(vec3(0.0, 2.0, 1.0)); void main(void) { - gl_Position = u_CameraTransforms * vec4(a_VertexPos, 1.0f); + gl_Position = u_CameraTransforms * vec4(a_Pos, 1.0f); vs_Out.v_TexCoords = a_TexUV; + vs_Out.v_Shading = max(0.4f, (1. + dot(abs(a_Normal), c_Sunlight)) / 2.0f); } \ No newline at end of file diff --git a/Jukcraft/src/core/Camera.cpp b/Jukcraft/src/core/Camera.cpp index 2c8aa8f..04caa2c 100644 --- a/Jukcraft/src/core/Camera.cpp +++ b/Jukcraft/src/core/Camera.cpp @@ -55,15 +55,21 @@ namespace Jukcraft { 0.1f, 500.0f ); -#ifndef JUK_DEBUG - glm::mat4 view = glm::rotate(glm::mat4(1.0f), player->getPitch(), -glm::vec3(1.0f, 0.0f, 0.0f)); - view = glm::rotate(view, player->getYaw() + glm::pi() / 2, glm::vec3(0.0f, 1.0f, 0.0f)); - view = glm::translate(view, -interpolatedPos - glm::vec3(0, player->getEyeLevel(), 0)); -#else + + glm::mat4 view = glm::mat4(1.0f); - view = glm::rotate(view, glm::pi() / 2 , glm::vec3(0.0f, 1.0f, 0.0f)); - view = glm::translate(view, -glm::vec3(0.0f, 65.0f, 32.0f) - glm::vec3(0, player->getEyeLevel(), 0)); -#endif + + if (isFirstPerson) { + view = glm::rotate(view, player->getPitch(), -glm::vec3(1.0f, 0.0f, 0.0f)); + view = glm::rotate(view, player->getYaw() + glm::pi() / 2, glm::vec3(0.0f, 1.0f, 0.0f)); + view = glm::translate(view, -interpolatedPos - glm::vec3(0, player->getEyeLevel(), 0)); + } + else { + view = glm::rotate(view, glm::pi() / 2, glm::vec3(0.0f, 1.0f, 0.0f)); + view = glm::translate(view, -glm::vec3(0.0f, 65.0f, 32.0f) - glm::vec3(0, player->getEyeLevel(), 0)); + } + + mappedUbo->transform = proj * view; mappedUbo->pos = glm::vec4(player->position, 1.0f); diff --git a/Jukcraft/src/core/Camera.h b/Jukcraft/src/core/Camera.h index b8c9869..568a1f2 100644 --- a/Jukcraft/src/core/Camera.h +++ b/Jukcraft/src/core/Camera.h @@ -7,6 +7,7 @@ namespace Jukcraft { public: Camera(gfx::Shader& shader, Auto& player); void update(const float delta_time); + bool isFirstPerson = true; private: gfx::Buffer ubo; gfx::Shader& shader; @@ -18,6 +19,7 @@ namespace Jukcraft { ShaderCameraData *mappedUbo; + FORBID_COPY(Camera); FORBID_MOVE(Camera); }; diff --git a/Jukcraft/src/core/Game.cpp b/Jukcraft/src/core/Game.cpp index 7d5ed65..967c8f3 100644 --- a/Jukcraft/src/core/Game.cpp +++ b/Jukcraft/src/core/Game.cpp @@ -52,6 +52,9 @@ namespace Jukcraft { case GLFW_KEY_LEFT_CONTROL: player->dash(); break; + case GLFW_KEY_F5: + camera.isFirstPerson = !camera.isFirstPerson; + break; } } void Game::hitCallback(int button, const BlockPos& currentBlock, const BlockPos& nextBlock) { @@ -79,9 +82,12 @@ namespace Jukcraft { Renderer::Begin(world->getSkyColor()); world->render(partialTicks); -#ifdef JUK_DEBUG - world->mobRenderer.render(*player, partialTicks); -#endif + + if (!camera.isFirstPerson) { + world->mobRenderer.render(*player, partialTicks); + } + + Renderer::End(); } } \ No newline at end of file diff --git a/Jukcraft/src/entity/Entity.h b/Jukcraft/src/entity/Entity.h index e51b134..21cd23f 100644 --- a/Jukcraft/src/entity/Entity.h +++ b/Jukcraft/src/entity/Entity.h @@ -17,10 +17,12 @@ namespace Jukcraft { virtual void tick() = 0; virtual void applyPhysics() = 0; virtual void aiStep() = 0; - virtual void handleRotation() {} + virtual void tickRotations() {} virtual void move(const glm::vec3& motion) = 0; virtual void push(const glm::vec3& motion) = 0; virtual void render(float partialTicks) {} + virtual void hurt(float amount, const glm::vec3& knockback) = 0; + constexpr const glm::vec3& getPos() const { return position; } constexpr const glm::vec3& getVelocity() const { return velocity; } diff --git a/Jukcraft/src/entity/LivingEntity.cpp b/Jukcraft/src/entity/LivingEntity.cpp index 5f40998..ad8adbc 100644 --- a/Jukcraft/src/entity/LivingEntity.cpp +++ b/Jukcraft/src/entity/LivingEntity.cpp @@ -116,13 +116,11 @@ namespace Jukcraft { velocity.y = glm::sqrt(-2 * g.y * hmax); } - void LivingEntity::handleRotation() { + void LivingEntity::tickRotations() { glm::vec3 ds = position - old.position; - float g = 0.0f; float nextBodyYaw = headRot.x; float ortho2 = ds.x * ds.x + ds.z * ds.z; if (ortho2 > 0.0f) { - g = glm::sqrt(ortho2); nextBodyYaw = glm::atan(ds.z, ds.x); } if (animationTicks.attack > 0.0F) { @@ -137,12 +135,6 @@ namespace Jukcraft { bodyRot.x += relativeAngle - glm::sign(relativeAngle) * glm::pi() / 3.0f; } - if (glm::abs(relativeAngle) > glm::pi() / 2) { - g *= -1.0F; - } - - animationTicks.step = g; - while (bodyRot.x - old.bodyRot.x < -glm::pi()) { old.bodyRot.x -= 2.0f * glm::pi(); } @@ -167,24 +159,47 @@ namespace Jukcraft { old.velocity = velocity; age++; - + iframes = glm::max(0, iframes - 1); + aiStep(); - handleRotation(); + tickRotations(); - walkAnimation.update(glm::min(4.0f * glm::length(position - old.position), 1.0f), 0.4f); + walkAnimation.update(glm::min(glm::length(position - old.position) * 4.0f, + 1.0f), //TICK_RATE / 20.0f), + 0.4f); + if (health.hp <= 0.0f || deathTime > 0) { + die(); + } + } + + void LivingEntity::die() { + deathTime++; + setInput(glm::vec3(0.0f)); + } + + void LivingEntity::hurt(float amount, const glm::vec3& knockback) { + bool success = health.hurt(amount, iframes > 0); + velocity += (float)(success) * knockback / (iframes > 0 ? 2.0f : 1.0f); + iframes = iframes > 0 ? iframes : glm::floor(TICK_RATE / 2); + if (health.hp <= 0.0f) { + die(); + } } void LivingEntity::aiStep() { applyPhysics(); + checkInjury(); + health.healNatural(); + stamina = glm::min(stamina + 1.0f / TICK_RATE, 1.0f); + } + + void LivingEntity::checkInjury() { float unabsorbedEnergy = getKineticEnergy() - getMaxKineticEnergy(); if (unabsorbedEnergy > 0.0f) { - health = glm::max(0.0f, health - unabsorbedEnergy * TICK_RATE * TICK_RATE); + hurt(health.hp - unabsorbedEnergy * TICK_RATE * TICK_RATE, glm::vec3(0.0f)); + consumeInertia(); } - health = glm::min(health + 0.25f / TICK_RATE, 20.0f); - stamina = glm::min(stamina + 1.0f / TICK_RATE, 1.0f); - - } void LivingEntity::applyPhysics() { diff --git a/Jukcraft/src/entity/LivingEntity.h b/Jukcraft/src/entity/LivingEntity.h index d82c7f1..f3cbdc7 100644 --- a/Jukcraft/src/entity/LivingEntity.h +++ b/Jukcraft/src/entity/LivingEntity.h @@ -10,6 +10,32 @@ namespace Jukcraft { class World; + struct Health { + float oldHp = 20.0f; + float hp = 20.0f; + float energy = 1.0f; + + void healNatural() { + // hp = glm::min(hp + 0.25f / TICK_RATE, 20.0f); + + } + + bool hurt(float amount, bool isIframe) { + if (!isIframe) { + oldHp = hp; + hp -= amount; + } + else if (amount > oldHp - hp) { + hp = oldHp - amount; + } + else { + return false; + } + return true; + + } + }; + class LivingEntity : public Entity { public: LivingEntity(World& world, const glm::vec3& initialPos = glm::vec3(0.0f), @@ -23,7 +49,9 @@ namespace Jukcraft { void aiStep() override; void tick() override; void applyPhysics() override; - void handleRotation() override; + void tickRotations() override; + void hurt(float amount, const glm::vec3& knockback) override; + void move(const glm::vec3& motion) override; void push(const glm::vec3& motion) override; @@ -40,13 +68,17 @@ namespace Jukcraft { constexpr const auto& getOld() const { return old; } constexpr const auto& getAnimationTicks() const { return animationTicks; } constexpr const auto& getWalkAnimation() const { return walkAnimation; } + constexpr bool isHurt() const { return iframes > 0 || deathTime > 0; } + constexpr int getDeathTime() const { return deathTime; } void setHeadYaw(float theta) { headRot.x = wrapRadians(theta); } void setHeadPitch(float phi) { headRot.y = glm::clamp(phi, -glm::pi() / 2, glm::pi() / 2); } void setBodyYaw(float theta) { bodyRot.x = wrapRadians(theta);} void consumeInertia(); + void die(); protected: + void checkInjury(); constexpr const glm::vec3& getFriction() const { if (onGround) return FRICTION; @@ -61,10 +93,13 @@ namespace Jukcraft { glm::vec2 bodyRot; glm::vec2 headRot; + int iframes = 0; + int deathTime = 0; + float width, height; - float health = 20.0f; - float stamina = 0.0f; + Health health; + float stamina = 1.0f; glm::vec3 inertia = glm::vec3(0.0f); size_t age = 0; diff --git a/Jukcraft/src/entity/Mob.cpp b/Jukcraft/src/entity/Mob.cpp index ace74c4..a692ff9 100644 --- a/Jukcraft/src/entity/Mob.cpp +++ b/Jukcraft/src/entity/Mob.cpp @@ -16,34 +16,40 @@ namespace Jukcraft { } void Mob::aiStep() { - std::uniform_int_distribution uniformDist2(0, 100); - if (uniformDist2(rng) > 99) { - std::uniform_int_distribution uniformDist(0, 12); - float dx = (int)uniformDist(rng) - 6; - float dz = (int)uniformDist(rng) - 6; - - if (dx != 0 && dz != 0) { - setYaw(wrapRadians(glm::atan(dz, dx) - glm::pi() / 2)); + + if (deathTime <= 0) { + std::uniform_int_distribution uniformDist2(0, 100); + if (uniformDist2(rng) > 99) { + std::uniform_int_distribution uniformDist(0, 12); + float dx = (int)uniformDist(rng) - 6; + float dz = (int)uniformDist(rng) - 6; + + if (dx != 0 && dz != 0) { + setYaw(wrapRadians(glm::atan(dz, dx) - glm::pi() / 2)); + } } - } - float relativeAngle = wrapRadians(rotation.x - headRot.x); + float relativeAngle = wrapRadians(rotation.x - headRot.x); - if (glm::abs(relativeAngle) > 0) { - headRot.x += relativeAngle * 2.0f / TICK_RATE; - } + if (glm::abs(relativeAngle) > 0) { + headRot.x += relativeAngle * 2.0f / TICK_RATE; + } - if (1) { - setInput(glm::vec3(0.0f, 0.0f, 1.0f)); + if (1) { + setInput(glm::vec3(0.0f, 0.0f, 1.0f)); + } + + if (App::GetWindow().isKeyPressed(GLFW_KEY_LEFT_SHIFT) && onGround) { + hurt(19.9f, glm::vec3( + -20 / TICK_RATE * glm::cos(rotation.x), + 10 / TICK_RATE, + -20 / TICK_RATE * glm::sin(rotation.x) + )); + } + + // LOG_INFO("{}", health.hp); } - if (App::GetWindow().isKeyPressed(GLFW_KEY_LEFT_SHIFT) && onGround) { - velocity += glm::vec3( - -20 / TICK_RATE * glm::cos(rotation.x), - 10 / TICK_RATE, - -20 / TICK_RATE * glm::sin(rotation.x) - ); - } diff --git a/Jukcraft/src/entity/player/Player.cpp b/Jukcraft/src/entity/player/Player.cpp index 2f5c7e6..e33b503 100644 --- a/Jukcraft/src/entity/player/Player.cpp +++ b/Jukcraft/src/entity/player/Player.cpp @@ -21,8 +21,6 @@ namespace Jukcraft { if (dashing && onGround) { dashing = false; } - - fov = glm::radians(70.0f + glm::length(velocity) * TICK_RATE); } diff --git a/Jukcraft/src/models/entity/EntityModel.cpp b/Jukcraft/src/models/entity/EntityModel.cpp index 7435745..cd9e7aa 100644 --- a/Jukcraft/src/models/entity/EntityModel.cpp +++ b/Jukcraft/src/models/entity/EntityModel.cpp @@ -104,9 +104,14 @@ namespace Jukcraft { }; for (int i = 0; i < 6; ++i) { + glm::vec3 normal = glm::normalize(glm::cross( + transformedVertices[i * 4] - transformedVertices[i * 4 + 1], + transformedVertices[i * 4] - transformedVertices[i * 4 + 2] + )); for (int j = 0; j < 4; ++j) { quads[i].vertices[j].pos = transformedVertices[i * 4 + j]; quads[i].vertices[j].texUV = texCoords[i][j]; + quads[i].vertices[j].normal = normal; } } } diff --git a/Jukcraft/src/models/entity/EntityModel.h b/Jukcraft/src/models/entity/EntityModel.h index 63a7e2b..6798299 100644 --- a/Jukcraft/src/models/entity/EntityModel.h +++ b/Jukcraft/src/models/entity/EntityModel.h @@ -9,6 +9,7 @@ namespace Jukcraft { struct Vertex { glm::vec3 pos; glm::vec2 texUV; + glm::vec3 normal; }; struct Quad { diff --git a/Jukcraft/src/renderer/entity/LivingEntityRenderer.cpp b/Jukcraft/src/renderer/entity/LivingEntityRenderer.cpp index 397b6bf..de09a20 100644 --- a/Jukcraft/src/renderer/entity/LivingEntityRenderer.cpp +++ b/Jukcraft/src/renderer/entity/LivingEntityRenderer.cpp @@ -12,7 +12,8 @@ namespace Jukcraft { gfx::VertexArrayLayout{ { { 3, true }, - { 2, true } + { 2, true }, + { 3, true } } } ); @@ -20,7 +21,11 @@ namespace Jukcraft { vao.bindVertexBuffer( vbo, 0, gfx::VertexBufferLayout{ - {{ 0, 0 }, { 1, offsetof(Bone::Vertex, texUV)}}, + { + { 0, 0 }, + { 1, offsetof(Bone::Vertex, texUV)}, + { 2, offsetof(Bone::Vertex, normal)} + }, 0, sizeof(Bone::Vertex) } @@ -41,35 +46,50 @@ namespace Jukcraft { glm::vec2 interpolatedHeadRot = glm::mix(livingEntity.getOld().headRot, livingEntity.getHeadRot(), partialTicks); int i = 0; + bool isHurt = livingEntity.isHurt(); + if (isHurt) + shader.setUniform4f(0, glm::vec4(1.0f, 0.0f, 0.0f, 0.4f)); + else + shader.setUniform4f(0, glm::vec4(1.0f)); + for (auto&& [name, bone] : model.bones) { glm::mat4 pose(1.0f); - pose = glm::translate(pose, interpolatedPos); + glm::mat4 modelMatrix = glm::translate(glm::mat4(1.0f), interpolatedPos); + + pose = glm::rotate(pose, -interpolatedBodyRot.x - glm::pi() / 2, UP); + pose = glm::rotate(pose, interpolatedBodyRot.y, EAST); + + if (livingEntity.getDeathTime() > 0.0f) { + float i = glm::min(1.0f, + glm::sqrt( + (float)(livingEntity.getDeathTime() + partialTicks - 1.0F) / TICK_RATE * 1.6F)); + pose = glm::rotate(pose, i * glm::pi() / 2.0f, SOUTH); + } if (bone.isHead) { + pose = glm::rotate(pose, interpolatedBodyRot.y, WEST); + pose = glm::rotate(pose, -interpolatedBodyRot.x - glm::pi() / 2, DOWN); + pose = glm::translate(pose, bone.pivot); - pose = glm::rotate(pose, -interpolatedHeadRot.x - glm::pi() / 2, glm::vec3(0.0f, 1.0f, 0.0f)); - pose = glm::rotate(pose, interpolatedHeadRot.y, glm::vec3(1.0f, 0.0f, 0.0f)); + pose = glm::rotate(pose, -interpolatedHeadRot.x - glm::pi() / 2, UP); + pose = glm::rotate(pose, interpolatedHeadRot.y, EAST); pose = glm::translate(pose, -bone.pivot); } - else { - pose = glm::rotate(pose, -interpolatedBodyRot.x - glm::pi() / 2, glm::vec3(0.0f, 1.0f, 0.0f)); - pose = glm::rotate(pose, interpolatedBodyRot.y, glm::vec3(1.0f, 0.0f, 0.0f)); - } const float phase = glm::pi() * (bone.isArm ^ bone.isOdd); if (bone.isLeg) { pose = glm::translate(pose, bone.pivot); - - pose = glm::rotate( pose, glm::cos( - livingEntity.getWalkAnimation().lerpPos(partialTicks) + livingEntity.getWalkAnimation().lerpPos(partialTicks) * 0.6662f + phase - ) * 1.4f * glm::min(1.0f, livingEntity.getWalkAnimation().lerpSpeed(partialTicks) * TICK_RATE / 20.0f), - glm::vec3(1.0f, 0.0f, 0.0f) + ) * 0.07f * TICK_RATE * glm::min(20.0f / TICK_RATE, + livingEntity.getWalkAnimation().lerpSpeed(partialTicks) + ), + EAST ); pose = glm::translate(pose, -bone.pivot); } @@ -77,16 +97,18 @@ namespace Jukcraft { if (bone.isArm) { pose = glm::translate(pose, bone.pivot); float theta = bone.isOdd ? (float)livingEntity.getAge() / (-TICK_RATE) : 2 * livingEntity.getAge() / TICK_RATE; - pose = glm::rotate(pose, glm::sin(theta + phase) / 8, glm::vec3(0.0f, 1.0f, 0.0f)); + pose = glm::rotate(pose, glm::sin(theta + phase) / 8, UP); pose = glm::rotate( pose, glm::cos( livingEntity.getWalkAnimation().lerpPos(partialTicks) * 0.6662f + phase - ) * glm::min(1.0f, livingEntity.getWalkAnimation().lerpSpeed(partialTicks) * TICK_RATE / 20.0f), - glm::vec3(1.0f, 0.0f, 0.0f) + ) * 0.05f * TICK_RATE * glm::min(20 / TICK_RATE, + livingEntity.getWalkAnimation().lerpSpeed(partialTicks) + ), + EAST ); - pose = glm::rotate(pose, glm::cos(theta + phase) / 8, glm::vec3(1.0f, 0.0f, 0.0f)); + pose = glm::rotate(pose, glm::cos(theta + phase) / 8, EAST); pose = glm::translate(pose, -bone.pivot); } @@ -96,7 +118,8 @@ namespace Jukcraft { for (auto& quad : quads) { for (auto& vertex : quad.vertices) { - vertex.pos = pose * glm::vec4(vertex.pos, 1.0f); + vertex.pos = modelMatrix * pose * glm::vec4(vertex.pos, 1.0f); + vertex.normal = pose * glm::vec4(vertex.normal, 1.0f); } } diff --git a/Jukcraft/src/renderer/gfx/objects/Shader.h b/Jukcraft/src/renderer/gfx/objects/Shader.h index 63586e5..19d2dd9 100644 --- a/Jukcraft/src/renderer/gfx/objects/Shader.h +++ b/Jukcraft/src/renderer/gfx/objects/Shader.h @@ -47,6 +47,10 @@ namespace Jukcraft { glProgramUniform3f(handle, location, value.x, value.y, value.z); } + void setUniform4f(uint8_t location, const glm::vec4& value) { + glProgramUniform4f(handle, location, value.x, value.y, value.z, value.w); + } + void setUniform1f(uint8_t location, float value) { glProgramUniform1f(handle, location, value); }