nicer particles, adding code so that particles don't penetrate through planets. added not-yet compeleted intersection code.

This commit is contained in:
Andreas Ortmann 2016-10-02 20:10:43 +02:00
parent 57e6e56217
commit 4712926be2
6 changed files with 207 additions and 17 deletions

View file

@ -1,10 +1,13 @@
#version 120
varying vec3 position;
varying vec2 vertex;
varying vec3 velocity;
varying float decay;
varying float explCenterDist;
float pi = 3.14159;
vec3 hsv2rgb(vec3 c)
{
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
@ -12,15 +15,28 @@ vec3 hsv2rgb(vec3 c)
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
float hash(float n)
{
return fract(sin(n)*43758.5453);
}
void main()
{
float r = length(vertex);
if (r > 1.0) {
// normalize radius from 0..1
vec2 vn = 2.0*vertex;
float rn = length(vn);
float angle = atan(vn.y, vn.x);
float hs = 20.0;
float removeCorners = 0.5 * (hash(fract(hs*vertex.x)) + hash(fract(hs*vertex.y)));
if (rn+removeCorners > 1.0) {
discard;
}
//float rf = 0.5-0.5*rn;
float rf = 1.0;
float d = decay/(1.0+max(0.0, 1.0-2.0*explCenterDist));
float h = (1.0-d)/6.0;
float h = max(0.0, (1.0-d)/6.0) * rf;
float v = max(0.0, (1.0-log(d)));
float s = max(0.0, min(30.0 * sqrt(decay) * explCenterDist, 1.0));
@ -30,4 +46,5 @@ void main()
gl_FragColor = vec4(hsv2rgb(vec3(h, s, v)), 1.0);
//gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
//gl_FragColor.rgb = vec3(0.5+0.5*(a/pi));
}

View file

@ -14,6 +14,7 @@ varying float decay;
varying vec3 velocity;
varying vec2 vertex;
varying float explCenterDist;
varying vec3 position;
uniform float aspectRatio;
@ -31,9 +32,9 @@ void main()
// faster particles are smaller
// TODO: scale by time too! scale down fast after 3 halfAges
float scaleBySpeed = (1.0 - 0.95*length(in_velocity)/maxVelocity);
float finalSize = size * scaleBySpeed;
float finalSize = size * scaleBySpeed * (1.0-max(0.0, decay-3.0*halfAge)/2.0);
vec2 base = in_geometry;
vec3 p = finalSize*vec3(base, 0.0);
vec3 p = vec3(finalSize*base, 0.0);
vec3 move = (0.2*age + log(1.0+age*5.0)) * in_velocity;
float md = length(move);
if (md > in_maxDist) {
@ -46,6 +47,7 @@ void main()
vertex = base.xy;
velocity = in_velocity;
position = in_position;
explCenterDist = length(explCenter - offset);
}

View file

@ -25,10 +25,10 @@ namespace endofthejedi {
// TODO
// it is transformed before uploading so it looks at the camera
, m_data_geometry({
1.0f, -1.0f,
1.0f, 1.0f,
-1.0f, 1.0f,
-1.0f, -1.0f})
0.5f, -0.5f,
0.5f, 0.5f,
-0.5f, 0.5f,
-0.5f, -0.5f})
{
m_num_vertex_buffers = 4;

View file

@ -49,9 +49,9 @@ namespace endofthejedi {
// TODO: add dust particles
// TODO: add little rocks flying around
glClearColor(0.0, 0.0, 0.0, 1.0);
//float s = 0.1;
//glClearColor(s, s, s, 1.0);
//glClearColor(0.0, 0.0, 0.0, 1.0);
float s = 0.1;
glClearColor(s, s, 1.2*s, 1.0);
m_shader_game_objects.bind();
@ -94,11 +94,11 @@ namespace endofthejedi {
}
}
void RendererPolygon3d::addExplosionEffect(size_t id, const glm::vec2 &pos, size_t n, float duration)
void RendererPolygon3d::addExplosionEffect(size_t id, const glm::vec2 &explCenter, size_t n, float duration)
{
//float particleRadius = 0.005;
//float particleRadius = 0.003;
float particleRadius = 0.005;
float particleRadius = 0.02;
// TODO: use this as shader input too and make the area 2x around this
// so that it stays hot/yellow for 2/3 of the time
@ -107,7 +107,7 @@ namespace endofthejedi {
ParticleBatch *batch = new ParticleBatch(id, n, particleRadius, duration);
batch->setup(&m_shader_particles);
batch->setCenter(glm::vec3(pos, 0.0));
batch->setCenter(glm::vec3(explCenter, 0.0));
batch->setMaxVelocity(maxVelocity);
for (size_t i=0; i<n; i++) {
@ -121,11 +121,84 @@ namespace endofthejedi {
// especially in 3d this would look bad without 3d velocity vector.
//glm::vec3 v = 0.5f*glm::vec3(sin(t), cos(t), util::randf_m1_1());
glm::vec3 pos = glm::vec3(explCenter, 0.0) + glm::ballRand(explCoreSize);
glm::vec3 v = glm::ballRand(maxVelocity);
v *= util::randf_0_1() * util::randf_0_1() * util::randf_0_1();
float maxDist = 0.2;
batch->setParticle(i, glm::vec3(pos, 0.0) + glm::ballRand(explCoreSize), v, maxDist);
// find collisions with planetns and limit max distance so particles
// won't fly through planets
//float maxDist = 0.1;
//float maxDist = 0.1*util::randf_0_1();
bool isInsidePlanet = false;
float maxParticleDist = INFINITY;
const game::Planet *nearestPlanet = nullptr;
for (const game::Planet *planet : m_state->planets) {
const glm::vec3 ppos3 = glm::vec3(planet->position, 0.0f);
// TODO: check if inside planet!
float dist = glm::distance(ppos3, pos);
if (dist <= planet->radius) {
isInsidePlanet = true;
nearestPlanet = planet;
}
if (isInsidePlanet) {
// skip searching for nearer planets once we are inside some
// planet as the position/velocity will be changed to start
// at the surface of the planet we were in with
// reflected or planet-normal velocity.
continue;
}
// TODO: if inside, move position so that it looks like
// reflecting the particle from the planet
bool fliesInPlanetDirection = glm::dot(v, ppos3-pos) > 0.0f;
if (dist < maxParticleDist && fliesInPlanetDirection) {
nearestPlanet = planet;
maxParticleDist = dist;
}
}
if (isInsidePlanet) {
util::IntersectionTest intersect;
if (!intersect.raySphere(
pos, v,
glm::vec3(nearestPlanet->position, 0.0f), nearestPlanet->radius))
{
//std::cout<<"warning: intersection should be valid!" << std::endl;
// TODO: must be as they lie on a plane and the dist is < as
// the radius.
// handle if this is wrong.
} else {
// set position to the intersection point between explosion
// center and planet surface
//const glm::vec3 planetNormal = glm::vec3(glm::normalize(explCenter - nearestPlanet->position), 0.0f);
//pos = glm::vec3(nearestPlanet->position, 0.0f) + nearestPlanet->radius*planetNormal;
// build new velocity by reflecting the old velocity on the
// planet normal
// TODO: add a bit random
// TODO: add reflection
// TODO: distribute particles around main reflection angle and
// TODO: add material exhaust that is specific for the planet.
// TODO: spawn waves on water planet
// TODO: start fire on gas planet
//v = glm::length(v) * planetNormal;
//v = v - 2.0f*glm::dot(v, planetNormal) * planetNormal;
//v = glm::length(v) * planetNormal;
//glm::vec3 r = v - 2.0f*glm::dot(v, planetNormal) * planetNormal;
//glm::vec3 vn = glm::length(v) * planetNormal;
//v = (r+vn) / 2.0f;
//glm::vec3 vc = glm::vec3(nearestPlanet->position-explCenter, 0.0f);
//glm::vec3 r = vc - 2.0f*glm::dot(vc, planetNormal) * planetNormal;
//v = r;
}
}
batch->setParticle(i, pos, v, maxParticleDist);
}
batch->upload();
@ -189,6 +262,8 @@ namespace endofthejedi {
void RendererPolygon3d::renderMissiles()
{
// TODO: add fire trail for missiles near the sun
m_missileModel->bind();
for (const game::Player *player : m_state->players) {

View file

@ -33,4 +33,71 @@ namespace util {
{
return 180.0 * rad / M_PI;
}
IntersectionTest::IntersectionTest() : m_valid(false), m_distance(INFINITY)
{
}
IntersectionTest::IntersectionTest(float d) : m_valid(true), m_distance(d)
{
}
float IntersectionTest::distance() const { assert(m_valid); return m_distance; }
bool IntersectionTest::valid() const { return m_valid; }
bool IntersectionTest::raySphere(
const glm::vec3 &rayPos, const glm::vec3 &rayDir,
const glm::vec3 &spherePos, float sphereRadius)
{
m_valid = false;
// TODO: get code
return m_valid;
#if 0
const glm::vec3 &o = ray.pos();
const glm::vec3 &l = ray.dir();
const glm::vec3 &c = m_pos;
const float &r = m_radius;
const glm::vec3 omc = o-c;
const float dot = glm::dot(l, omc);
const float s = dot*dot - util::dotSelf(omc) + r*r;
if (s < 0.001) {
return RayIntersection();
}
const float t = -dot;
#if 0
// TODO: is that meant as t?
if (s == 0) {
// not interested in touch point
return RayIntersection();
//d1 = t;
//return RayTouchesOnePoint;
}
#endif
const float sr = sqrt(s);
d1 = t - sr;
d2 = t + sr;
// if end intersection lies behind it, this is completely uninteresting for us
// 0.01 because to get rid of rounding/precision errors
if (d2 <= 0.01) {
return RayIntersection();
}
// if the start of the interval lies behind us, make it 0 because we just
// want to know whats before us.
// 0.01 because to get rid of rounding/precision errors
if (d1 < 0.0) {
d1 = 0.0;
}
#endif
}
}

View file

@ -1,6 +1,7 @@
#pragma once
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
namespace util {
@ -12,4 +13,32 @@ namespace util {
float deg2rad(float deg);
float rad2deg(float rad);
/**
* Test for intersection in positive direction of a ray.
* TODO: support inside?
*/
class IntersectionTest {
public:
IntersectionTest();
// creates a valid intersection point at distance d
IntersectionTest(float d);
// intersection distance
float distance() const;
// returns true if there's an interseciton.
bool valid() const;
// return true if there's an intersection. then intersectionPoint is filled
// with details.
bool raySphere(
const glm::vec3 &rayPos, const glm::vec3 &rayDir,
const glm::vec3 &spherePos, float sphereRadius);
private:
bool m_valid;
float m_distance;
};
}