Impl. shader for SparkEffect
All checks were successful
Build and Publish WASM version of demo / Build-And-Deploy (push) Successful in 25s
All checks were successful
Build and Publish WASM version of demo / Build-And-Deploy (push) Successful in 25s
The shader gives the "sparks" a white center. Drawing sparks now generates a flat "circle" (facing the camera) instead of drawing a 3D sphere.
This commit is contained in:
parent
c14123b3d0
commit
5c9cd56884
6 changed files with 194 additions and 7 deletions
|
@ -196,6 +196,42 @@ std::array<Vector3, 4> get_quad_from_start_end(Vector3 start, Vector3 end,
|
||||||
return quad;
|
return quad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::array<Vector3, 9> get_circle_facing_viewer(Vector3 pos, Vector3 normal,
|
||||||
|
float radius) {
|
||||||
|
std::array<Vector3, 9> vertices;
|
||||||
|
|
||||||
|
vertices[0] = pos;
|
||||||
|
|
||||||
|
// Normalize just in case the normal isn't a unit vector.
|
||||||
|
normal = Vector3Normalize(normal);
|
||||||
|
|
||||||
|
vertices[1] = Vector3Perpendicular(normal) * radius;
|
||||||
|
vertices[2] =
|
||||||
|
Vector3RotateByAxisAngle(vertices[1], normal, PI * 2.0F * 1.0F / 8.0F) +
|
||||||
|
pos;
|
||||||
|
vertices[3] =
|
||||||
|
Vector3RotateByAxisAngle(vertices[1], normal, PI * 2.0F * 2.0F / 8.0F) +
|
||||||
|
pos;
|
||||||
|
vertices[4] =
|
||||||
|
Vector3RotateByAxisAngle(vertices[1], normal, PI * 2.0F * 3.0F / 8.0F) +
|
||||||
|
pos;
|
||||||
|
vertices[5] =
|
||||||
|
Vector3RotateByAxisAngle(vertices[1], normal, PI * 2.0F * 4.0F / 8.0F) +
|
||||||
|
pos;
|
||||||
|
vertices[6] =
|
||||||
|
Vector3RotateByAxisAngle(vertices[1], normal, PI * 2.0F * 5.0F / 8.0F) +
|
||||||
|
pos;
|
||||||
|
vertices[7] =
|
||||||
|
Vector3RotateByAxisAngle(vertices[1], normal, PI * 2.0F * 6.0F / 8.0F) +
|
||||||
|
pos;
|
||||||
|
vertices[8] =
|
||||||
|
Vector3RotateByAxisAngle(vertices[1], normal, PI * 2.0F * 7.0F / 8.0F) +
|
||||||
|
pos;
|
||||||
|
vertices[1] = vertices[1] + pos;
|
||||||
|
|
||||||
|
return vertices;
|
||||||
|
}
|
||||||
|
|
||||||
Vector3 operator+(Vector3 a, Vector3 b) {
|
Vector3 operator+(Vector3 a, Vector3 b) {
|
||||||
return Vector3{a.x + b.x, a.y + b.y, a.z + b.z};
|
return Vector3{a.x + b.x, a.y + b.y, a.z + b.z};
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,14 @@ extern std::array<Vector3, 4> get_quad_from_start_end(Vector3 start,
|
||||||
Vector3 normal,
|
Vector3 normal,
|
||||||
float width);
|
float width);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First vertex is the center of the circle.
|
||||||
|
* Every consecutive vertex starting at index 1 is a circle edge c-clockwise.
|
||||||
|
*/
|
||||||
|
extern std::array<Vector3, 9> get_circle_facing_viewer(Vector3 pos,
|
||||||
|
Vector3 normal,
|
||||||
|
float radius);
|
||||||
|
|
||||||
// Unimplemented as this function isn't really needed and it exposes some
|
// Unimplemented as this function isn't really needed and it exposes some
|
||||||
// weirdness regarding column-major matrices.
|
// weirdness regarding column-major matrices.
|
||||||
// extern Vector4 operator*(const Matrix &m, const Vector4 &v);
|
// extern Vector4 operator*(const Matrix &m, const Vector4 &v);
|
||||||
|
|
|
@ -27,8 +27,6 @@ class ElectricityEffect {
|
||||||
static Shader get_shader();
|
static Shader get_shader();
|
||||||
static void cleanup_shader();
|
static void cleanup_shader();
|
||||||
static void update_shader_height();
|
static void update_shader_height();
|
||||||
static void update_shader_sides(Vector2 a, Vector2 adir, Vector2 b,
|
|
||||||
Vector2 bdir, float width);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct EndPoint {
|
struct EndPoint {
|
||||||
|
@ -44,6 +42,8 @@ class ElectricityEffect {
|
||||||
float lifetime;
|
float lifetime;
|
||||||
float timer;
|
float timer;
|
||||||
|
|
||||||
|
static void update_shader_sides(Vector2 a, Vector2 adir, Vector2 b,
|
||||||
|
Vector2 bdir, float width);
|
||||||
static void init_shader();
|
static void init_shader();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,8 @@ TRunnerScreen::TRunnerScreen(std::weak_ptr<ScreenStack> stack)
|
||||||
|
|
||||||
// Initialize ElectricityEffect shader.
|
// Initialize ElectricityEffect shader.
|
||||||
ElectricityEffect::update_shader_height();
|
ElectricityEffect::update_shader_height();
|
||||||
|
// Initialize SparkEffect shader.
|
||||||
|
SparkEffect::update_shader_height();
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::cout << "Screen finished init.\n";
|
std::cout << "Screen finished init.\n";
|
||||||
|
@ -85,6 +87,7 @@ TRunnerScreen::TRunnerScreen(std::weak_ptr<ScreenStack> stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
TRunnerScreen::~TRunnerScreen() {
|
TRunnerScreen::~TRunnerScreen() {
|
||||||
|
SparkEffect::cleanup_shader();
|
||||||
ElectricityEffect::cleanup_shader();
|
ElectricityEffect::cleanup_shader();
|
||||||
|
|
||||||
UnloadRenderTexture(fgRenderTexture);
|
UnloadRenderTexture(fgRenderTexture);
|
||||||
|
@ -103,6 +106,7 @@ bool TRunnerScreen::update(float dt, bool is_resized) {
|
||||||
fgRenderTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
|
fgRenderTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
|
||||||
|
|
||||||
ElectricityEffect::update_shader_height();
|
ElectricityEffect::update_shader_height();
|
||||||
|
SparkEffect::update_shader_height();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags.test(1)) {
|
if (flags.test(1)) {
|
||||||
|
@ -378,7 +382,7 @@ bool TRunnerScreen::draw(RenderTexture *render_texture) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &se : sparkEffects) {
|
for (auto &se : sparkEffects) {
|
||||||
se.draw();
|
se.draw(&camera);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO DEBUG
|
// TODO DEBUG
|
||||||
|
|
|
@ -1,9 +1,34 @@
|
||||||
#include "spark_effect.h"
|
#include "spark_effect.h"
|
||||||
|
|
||||||
|
#include <raylib.h>
|
||||||
|
#include <raymath.h>
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#define DEBUG_PRINT_VEC2(v2) \
|
||||||
|
do { \
|
||||||
|
std::cout << "Loading " << #v2 << " with value " << (v2).x << ", " \
|
||||||
|
<< (v2).y << std::endl; \
|
||||||
|
} while (false);
|
||||||
|
#define DEBUG_PRINT_FLOAT(f) \
|
||||||
|
do { \
|
||||||
|
std::cout << "Loading " << #f << " with value " << (f) << std::endl; \
|
||||||
|
} while (false);
|
||||||
|
#else
|
||||||
|
#define DEBUG_PRINT_VEC2(v2)
|
||||||
|
#define DEBUG_PRINT_FLOAT(f)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// standard library includes
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#include <iostream>
|
||||||
|
#endif
|
||||||
|
|
||||||
// local includes
|
// local includes
|
||||||
#include "3d_helpers.h"
|
#include "3d_helpers.h"
|
||||||
#include "ems.h"
|
#include "ems.h"
|
||||||
|
|
||||||
|
std::optional<Shader> SparkEffect::shader = std::nullopt;
|
||||||
|
|
||||||
SparkEffect::SparkEffect(int count, float lifetime, Vector3 pos,
|
SparkEffect::SparkEffect(int count, float lifetime, Vector3 pos,
|
||||||
float pos_xz_variance, float radius, Color color)
|
float pos_xz_variance, float radius, Color color)
|
||||||
: sparks(), color(color), lifetime(lifetime), timer(0.0F) {
|
: sparks(), color(color), lifetime(lifetime), timer(0.0F) {
|
||||||
|
@ -36,10 +61,115 @@ bool SparkEffect::update(float dt) {
|
||||||
return timer > lifetime;
|
return timer > lifetime;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SparkEffect::draw() {
|
void SparkEffect::draw(Camera *camera) {
|
||||||
float ratio = timer < lifetime ? (1.0F - timer / lifetime) : 0.0F;
|
float ratio = timer < lifetime ? (1.0F - timer / lifetime) : 0.0F;
|
||||||
|
float radius = SPARK_RADIUS * ratio;
|
||||||
|
|
||||||
for (const auto &spark : sparks) {
|
for (const auto &spark : sparks) {
|
||||||
DrawSphere(spark.pos, SPARK_RADIUS * ratio, color);
|
auto circle = get_circle_facing_viewer(
|
||||||
|
spark.pos, camera->position - spark.pos, radius);
|
||||||
|
|
||||||
|
Vector2 screen_pos = GetWorldToScreen(spark.pos, *camera);
|
||||||
|
Vector2 circle_edge_pos = GetWorldToScreen(circle[1], *camera);
|
||||||
|
update_shader_uniforms(Vector2Distance(screen_pos, circle_edge_pos),
|
||||||
|
screen_pos);
|
||||||
|
BeginShaderMode(get_shader());
|
||||||
|
for (decltype(circle.size()) idx = 1; idx < circle.size() - 1; ++idx) {
|
||||||
|
DrawTriangle3D(circle[0], circle[idx], circle[idx + 1], color);
|
||||||
|
}
|
||||||
|
DrawTriangle3D(circle[0], circle[circle.size() - 1], circle[1], color);
|
||||||
|
EndShaderMode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Shader SparkEffect::get_shader() {
|
||||||
|
if (!shader.has_value()) {
|
||||||
|
init_shader();
|
||||||
|
}
|
||||||
|
|
||||||
|
return shader.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SparkEffect::cleanup_shader() {
|
||||||
|
if (shader.has_value()) {
|
||||||
|
UnloadShader(shader.value());
|
||||||
|
shader.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SparkEffect::update_shader_height() {
|
||||||
|
if (!shader.has_value()) {
|
||||||
|
init_shader();
|
||||||
|
}
|
||||||
|
int uniform_loc = GetShaderLocation(get_shader(), "screen_height");
|
||||||
|
float height = GetScreenHeight();
|
||||||
|
DEBUG_PRINT_FLOAT(height);
|
||||||
|
SetShaderValue(get_shader(), uniform_loc, &height, SHADER_UNIFORM_FLOAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SparkEffect::update_shader_uniforms(float radius, Vector2 pos) {
|
||||||
|
if (!shader.has_value()) {
|
||||||
|
init_shader();
|
||||||
|
}
|
||||||
|
|
||||||
|
// radius *= 100.0F;
|
||||||
|
|
||||||
|
int uniform_loc = GetShaderLocation(get_shader(), "spark_radius");
|
||||||
|
DEBUG_PRINT_FLOAT(radius);
|
||||||
|
SetShaderValue(get_shader(), uniform_loc, &radius, SHADER_UNIFORM_FLOAT);
|
||||||
|
uniform_loc = GetShaderLocation(get_shader(), "spark_pos");
|
||||||
|
DEBUG_PRINT_VEC2(pos);
|
||||||
|
SetShaderValue(get_shader(), uniform_loc, &pos, SHADER_UNIFORM_VEC2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SparkEffect::init_shader() {
|
||||||
|
// Set up spark shader.
|
||||||
|
// Vertex shader is exactly the same as Raylib's default vertex shader.
|
||||||
|
shader = LoadShaderFromMemory(
|
||||||
|
// vertex
|
||||||
|
"#version 100 \n"
|
||||||
|
"attribute vec3 vertexPosition; \n"
|
||||||
|
"attribute vec2 vertexTexCoord; \n"
|
||||||
|
"attribute vec4 vertexColor; \n"
|
||||||
|
"varying vec2 fragTexCoord; \n"
|
||||||
|
"varying vec4 fragColor; \n"
|
||||||
|
"uniform mat4 mvp; \n"
|
||||||
|
"void main() \n"
|
||||||
|
"{ \n"
|
||||||
|
" fragTexCoord = vertexTexCoord; \n"
|
||||||
|
" fragColor = vertexColor; \n"
|
||||||
|
" gl_Position = mvp*vec4(vertexPosition, 1.0); \n"
|
||||||
|
"} \n",
|
||||||
|
|
||||||
|
// fragment
|
||||||
|
"#version 100 \n"
|
||||||
|
"precision mediump float; \n"
|
||||||
|
"varying vec2 fragTexCoord; \n"
|
||||||
|
"varying vec4 fragColor; \n"
|
||||||
|
"uniform sampler2D texture0; \n"
|
||||||
|
"uniform vec4 colDiffuse; \n"
|
||||||
|
"uniform float screen_height; \n"
|
||||||
|
"uniform float spark_radius; \n"
|
||||||
|
"uniform vec2 spark_pos; \n"
|
||||||
|
"void main() \n"
|
||||||
|
"{ \n"
|
||||||
|
" vec4 texelColor = texture2D(texture0, fragTexCoord); \n"
|
||||||
|
" vec4 color = texelColor*colDiffuse*fragColor; \n"
|
||||||
|
" if (spark_radius < 0.00001) { \n"
|
||||||
|
" gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); \n"
|
||||||
|
" return; \n"
|
||||||
|
" } \n"
|
||||||
|
" vec2 pos = gl_FragCoord.xy; \n"
|
||||||
|
" pos.y = screen_height - pos.y; \n"
|
||||||
|
" float dist = distance(pos, spark_pos); \n"
|
||||||
|
" float redge = spark_radius / 3.0; \n"
|
||||||
|
" float inv_redge = spark_radius * 2.0 / 3.0; \n"
|
||||||
|
" if (dist < redge) { \n"
|
||||||
|
" gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); \n"
|
||||||
|
" } else { \n"
|
||||||
|
" float lerpVal = min(1.0, (dist - redge) / inv_redge); \n"
|
||||||
|
" gl_FragColor = color * lerpVal + vec4(1.0, 1.0, 1.0, 1.0) * "
|
||||||
|
"(1.0 - lerpVal); \n"
|
||||||
|
" } \n"
|
||||||
|
"} \n");
|
||||||
|
}
|
||||||
|
|
|
@ -2,12 +2,13 @@
|
||||||
#define JUMPARTIFACT_DOT_COM_DEMO_0_SPARK_EFFECT_H_
|
#define JUMPARTIFACT_DOT_COM_DEMO_0_SPARK_EFFECT_H_
|
||||||
|
|
||||||
// standard library includes
|
// standard library includes
|
||||||
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// third party includes
|
// third party includes
|
||||||
#include <raylib.h>
|
#include <raylib.h>
|
||||||
|
|
||||||
constexpr float SPARK_RADIUS = 0.03F;
|
constexpr float SPARK_RADIUS = 0.04F;
|
||||||
constexpr float SPARK_VEL_RATE = 5.0F;
|
constexpr float SPARK_VEL_RATE = 5.0F;
|
||||||
constexpr float SPARK_VEL_VARIANCE = 1.0F;
|
constexpr float SPARK_VEL_VARIANCE = 1.0F;
|
||||||
constexpr float SPARK_ACC_RATE = 8.0F;
|
constexpr float SPARK_ACC_RATE = 8.0F;
|
||||||
|
@ -21,17 +22,25 @@ class SparkEffect {
|
||||||
bool update(float dt);
|
bool update(float dt);
|
||||||
|
|
||||||
/// Assumes draw mode is active when called.
|
/// Assumes draw mode is active when called.
|
||||||
void draw();
|
void draw(Camera *camera);
|
||||||
|
|
||||||
|
static Shader get_shader();
|
||||||
|
static void cleanup_shader();
|
||||||
|
static void update_shader_height();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Spark {
|
struct Spark {
|
||||||
Vector3 pos, vel;
|
Vector3 pos, vel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static std::optional<Shader> shader;
|
||||||
std::vector<Spark> sparks;
|
std::vector<Spark> sparks;
|
||||||
Color color;
|
Color color;
|
||||||
float lifetime;
|
float lifetime;
|
||||||
float timer;
|
float timer;
|
||||||
|
|
||||||
|
static void update_shader_uniforms(float radius, Vector2 pos);
|
||||||
|
static void init_shader();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue