Implemented dust particle system

--HG--
extra : convert_revision : svn%3A7752d6cf-9f14-4ad2-affc-04f1e67b81a5/trunk%40164
This commit is contained in:
kearwood
2012-11-23 01:02:22 +00:00
parent 230dd4722d
commit 96a9c02a13
19 changed files with 165 additions and 39 deletions

View File

@@ -73,6 +73,12 @@ KRVector3 KRAABB::size() const
return max - min;
}
float KRAABB::volume() const
{
KRVector3 s = size();
return s.x * s.y * s.z;
}
void KRAABB::scale(const KRVector3 &s)
{
KRVector3 prev_center = center();

View File

@@ -27,6 +27,7 @@ public:
KRVector3 center() const;
KRVector3 size() const;
float volume() const;
bool intersects(const KRAABB& b) const;
bool contains(const KRAABB &b) const;
bool contains(const KRVector3 &v) const;

View File

@@ -127,6 +127,8 @@ KRCamera::KRCamera(KRContext &context) : KRContextObject(context) {
fog_density = 0.0005f;
fog_color = KRVector3(0.45, 0.45, 0.5);
fog_type = 0;
dust_particle_intensity = 0.25f;
}
KRCamera::~KRCamera() {

View File

@@ -129,6 +129,8 @@ public:
KRVector3 fog_color;
int fog_type; // 0 = no fog, 1 = linear, 2 = exponential, 3 = exponential squared
float dust_particle_intensity;
private:
KRVector3 m_position;

View File

@@ -35,6 +35,7 @@ KRContext::KRContext() {
m_pSceneManager = new KRSceneManager(*this);
m_bDetectedExtensions = false;
m_current_frame = 0;
m_absolute_time = 0.0f;
}
KRContext::~KRContext() {
@@ -147,14 +148,20 @@ void KRContext::startFrame()
m_pTextureManager->startFrame();
}
void KRContext::endFrame()
void KRContext::endFrame(float deltaTime)
{
m_pTextureManager->endFrame();
rotateBuffers(true);
m_current_frame++;
m_absolute_time += deltaTime;
}
long KRContext::getCurrentFrame()
long KRContext::getCurrentFrame() const
{
return m_current_frame;
}
float KRContext::getAbsoluteTime() const
{
return m_absolute_time;
}

View File

@@ -57,9 +57,10 @@ public:
static bool extension_available[KRENGINE_NUM_EXTENSIONS];
void startFrame();
void endFrame();
void endFrame(float deltaTime);
long getCurrentFrame();
long getCurrentFrame() const;
float getAbsoluteTime() const;
private:
KRBundleManager *m_pBundleManager;
@@ -73,6 +74,7 @@ private:
bool m_bDetectedExtensions;
long m_current_frame;
float m_absolute_time;
};
#endif

View File

@@ -18,7 +18,7 @@ KRContextObject::~KRContextObject()
}
KRContext &KRContextObject::getContext()
KRContext &KRContextObject::getContext() const
{
return *m_pContext;
}

View File

@@ -17,7 +17,7 @@ public:
KRContextObject(KRContext &context);
~KRContextObject();
KRContext &getContext();
KRContext &getContext() const;
protected:
KRContext *m_pContext;
};

View File

@@ -60,7 +60,7 @@ int KRDirectionalLight::configureShadowBufferViewports(const KRViewport &viewpor
float min_depth = 0.0f;
float max_depth = 1.0f;
KRAABB worldSpacefrustrumSliceBounds = KRAABB(KRVector3(-1.0f, -max_depth, -1.0f), KRVector3(1.0f, -min_depth, 1.0f), KRMat4::Invert(viewport.getViewProjectionMatrix()));
KRAABB worldSpacefrustrumSliceBounds = KRAABB(KRVector3(-1.0f, -1.0f, -1.0f), KRVector3(1.0f, 1.0f, 1.0f), KRMat4::Invert(viewport.getViewProjectionMatrix()));
worldSpacefrustrumSliceBounds.scale(KRENGINE_SHADOW_BOUNDS_EXTRA_SCALE);
KRVector3 shadowLook = -KRVector3::Normalize(getWorldLightDirection());

View File

@@ -169,7 +169,7 @@ float const PI = 3.141592653589793f;
{
_context->startFrame();
_camera->renderFrame(*pScene, viewMatrix, deltaTime);
_context->endFrame();
_context->endFrame(deltaTime);
}
- (BOOL)loadShaders

View File

@@ -26,11 +26,15 @@
KRLight::KRLight(KRScene &scene, std::string name) : KRNode(scene, name)
{
m_intensity = 1.0f;
m_dust_particle_intensity = 1.0f;
m_color = KRVector3::One();
m_flareTexture = "";
m_pFlareTexture = NULL;
m_flareSize = 0.0;
m_casts_shadow = true;
m_light_shafts = true;
m_dust_particle_density = 0.1f;
m_dust_particle_size = 1.0f;
// Initialize shadow buffers
m_cShadowBuffers = 0;
@@ -58,12 +62,15 @@ tinyxml2::XMLElement *KRLight::saveXML( tinyxml2::XMLNode *parent)
e->SetAttribute("flare_texture", m_flareTexture.c_str());
e->SetAttribute("casts_shadow", m_casts_shadow ? "true" : "false");
e->SetAttribute("light_shafts", m_light_shafts ? "true" : "false");
e->SetAttribute("dust_particle_density", m_dust_particle_density);
e->SetAttribute("dust_particle_size", m_dust_particle_size);
e->SetAttribute("dust_particle_intensity", m_dust_particle_intensity);
return e;
}
void KRLight::loadXML(tinyxml2::XMLElement *e) {
KRNode::loadXML(e);
float x,y,z;
float x=1.0f,y=1.0f,z=1.0f;
if(e->QueryFloatAttribute("color_r", &x) != tinyxml2::XML_SUCCESS) {
x = 1.0;
}
@@ -95,6 +102,21 @@ void KRLight::loadXML(tinyxml2::XMLElement *e) {
m_light_shafts = true;
}
m_dust_particle_density = 0.1f;
if(e->QueryFloatAttribute("dust_particle_density", &m_dust_particle_density) != tinyxml2::XML_SUCCESS) {
m_dust_particle_density = 0.1f;
}
m_dust_particle_size = 1.0f;
if(e->QueryFloatAttribute("dust_particle_size", &m_dust_particle_size) != tinyxml2::XML_SUCCESS) {
m_dust_particle_size = 1.0f;
}
m_dust_particle_intensity = 1.0f;
if(e->QueryFloatAttribute("dust_particle_intensity", &m_dust_particle_intensity) != tinyxml2::XML_SUCCESS) {
m_dust_particle_intensity = 1.0f;
}
const char *szFlareTexture = e->Attribute("flare_texture");
if(szFlareTexture) {
m_flareTexture = szFlareTexture;
@@ -147,6 +169,46 @@ void KRLight::render(KRCamera *pCamera, std::vector<KRLight *> &lights, const KR
renderShadowBuffers(pCamera);
}
if(renderPass == KRNode::RENDER_PASS_ADDITIVE_PARTICLES) {
// Render brownian particles for dust floating in air
if(m_cShadowBuffers >= 1 && shadowValid[0] && m_dust_particle_density > 0.0f && m_dust_particle_size > 0.0f && m_dust_particle_intensity > 0.0f) {
float lod_coverage = getBounds().coverage(viewport.getViewProjectionMatrix(), viewport.getSize()); // This also checks the view frustrum culling
if(lod_coverage > 0.0f || true) {
float particle_range = 600.0f;
int particle_count = m_dust_particle_density * pow(particle_range, 3);
if(particle_count > KRModelManager::KRENGINE_MAX_RANDOM_PARTICLES) particle_count = KRModelManager::KRENGINE_MAX_RANDOM_PARTICLES;
// Enable z-buffer test
GLDEBUG(glEnable(GL_DEPTH_TEST));
GLDEBUG(glDepthRangef(0.0, 1.0));
KRMat4 particleModelMatrix;
particleModelMatrix.scale(particle_range); // Scale the box symetrically to ensure that we don't have an uneven distribution of particles for different angles of the view frustrum
particleModelMatrix.translate(viewport.getCameraPosition());
std::vector<KRLight *> this_light;
this_light.push_back(this);
KRShader *pParticleShader = m_pContext->getShaderManager()->getShader("particle", pCamera, this_light, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, renderPass);
if(getContext().getShaderManager()->selectShader(*pCamera, pParticleShader, viewport, particleModelMatrix, this_light, renderPass)) {
(m_color * pCamera->dust_particle_intensity * m_dust_particle_intensity * m_intensity).setUniform(pParticleShader->m_uniforms[KRShader::KRENGINE_UNIFORM_LIGHT_COLOR]);
KRMat4::DotWDiv(KRMat4::Invert(particleModelMatrix), KRVector3::Zero()).setUniform(pParticleShader->m_uniforms[KRShader::KRENGINE_UNIFORM_PARTICLE_ORIGIN]);
GLDEBUG(glUniform1f(pParticleShader->m_uniforms[KRShader::KRENGINE_UNIFORM_FLARE_SIZE], m_dust_particle_size));
m_pContext->getModelManager()->bindVBO((void *)m_pContext->getModelManager()->getRandomParticles(), KRModelManager::KRENGINE_MAX_RANDOM_PARTICLES * 3 * sizeof(KRModelManager::RandomParticleVertexData), true, false, false, true, false);
GLDEBUG(glDrawArrays(GL_TRIANGLES, 0, particle_count*3));
}
}
}
}
if(renderPass == KRNode::RENDER_PASS_VOLUMETRIC_EFFECTS_ADDITIVE && pCamera->volumetric_environment_enable && m_light_shafts) {
std::string shader_name = pCamera->volumetric_environment_downsample != 0 ? "volumetric_fog_downsampled" : "volumetric_fog";
@@ -164,9 +226,9 @@ void KRLight::render(KRCamera *pCamera, std::vector<KRLight *> &lights, const KR
float slice_spacing = (slice_far - slice_near) / slice_count;
KRVector2(slice_near, slice_spacing).setUniform(pFogShader->m_uniforms[KRShader::KRENGINE_UNIFORM_SLICE_DEPTH_SCALE]);
(KRVector3::One() * pCamera->volumetric_environment_intensity * -slice_spacing / 1000.0f).setUniform(pFogShader->m_uniforms[KRShader::KRENGINE_UNIFORM_LIGHT_COLOR]);
(m_color * pCamera->volumetric_environment_intensity * m_intensity * -slice_spacing / 1000.0f).setUniform(pFogShader->m_uniforms[KRShader::KRENGINE_UNIFORM_LIGHT_COLOR]);
m_pContext->getModelManager()->bindVBO((void *)m_pContext->getModelManager()->getVolumetricLightingVertexes(), KRModelManager::MAX_VOLUMETRIC_PLANES * 6 * sizeof(KRModelManager::VolumetricLightingVertexData), true, false, false, false, false);
m_pContext->getModelManager()->bindVBO((void *)m_pContext->getModelManager()->getVolumetricLightingVertexes(), KRModelManager::KRENGINE_MAX_VOLUMETRIC_PLANES * 6 * sizeof(KRModelManager::VolumetricLightingVertexData), true, false, false, false, false);
GLDEBUG(glDrawArrays(GL_TRIANGLES, 0, slice_count*6));
}

View File

@@ -18,8 +18,8 @@ static const float KRLIGHT_MIN_INFLUENCE = 0.15f; // 0.05f
// KRENGINE_MAX_SHADOW_BUFFERS must be at least 6 to allow omni-directional lights to render cube maps
#define KRENGINE_MAX_SHADOW_BUFFERS 6
#define KRENGINE_SHADOW_MAP_WIDTH 2048
#define KRENGINE_SHADOW_MAP_HEIGHT 2048
#define KRENGINE_SHADOW_MAP_WIDTH 1024
#define KRENGINE_SHADOW_MAP_HEIGHT 1024
class KRLight : public KRNode {
public:
@@ -65,6 +65,9 @@ protected:
bool m_casts_shadow;
bool m_light_shafts;
float m_dust_particle_density;
float m_dust_particle_size;
float m_dust_particle_intensity;
// Shadow Maps

View File

@@ -255,9 +255,9 @@ void KRModelManager::rotateBuffers(bool new_frame)
KRModelManager::VolumetricLightingVertexData *KRModelManager::getVolumetricLightingVertexes()
{
if(m_volumetricLightingVertexData == NULL) {
m_volumetricLightingVertexData = (VolumetricLightingVertexData *)malloc(sizeof(VolumetricLightingVertexData) * MAX_VOLUMETRIC_PLANES * 6);
m_volumetricLightingVertexData = (VolumetricLightingVertexData *)malloc(sizeof(VolumetricLightingVertexData) * KRENGINE_MAX_VOLUMETRIC_PLANES * 6);
int iVertex=0;
for(int iPlane=0; iPlane < MAX_VOLUMETRIC_PLANES; iPlane++) {
for(int iPlane=0; iPlane < KRENGINE_MAX_VOLUMETRIC_PLANES; iPlane++) {
m_volumetricLightingVertexData[iVertex].vertex.x = -1.0f;
m_volumetricLightingVertexData[iVertex].vertex.y = -1.0f;
m_volumetricLightingVertexData[iVertex].vertex.z = iPlane;
@@ -300,31 +300,35 @@ KRModelManager::VolumetricLightingVertexData *KRModelManager::getVolumetricLight
KRModelManager::RandomParticleVertexData *KRModelManager::getRandomParticles()
{
const int MAX_PARTICLES=500000;
if(m_randomParticleVertexData == NULL) {
m_randomParticleVertexData = (RandomParticleVertexData *)malloc(sizeof(RandomParticleVertexData) * MAX_PARTICLES * 3);
m_randomParticleVertexData = (RandomParticleVertexData *)malloc(sizeof(RandomParticleVertexData) * KRENGINE_MAX_RANDOM_PARTICLES * 3);
// Generate vertices for randomly placed equilateral triangles with a side length of 1 and an origin point centered so that an inscribed circle can be efficiently rendered without wasting fill
float equilateral_triangle_height = sqrt(3.0f) / 2.0f;
float inscribed_circle_radius = 1.0f / (2.0f * sqrt(3.0f));
int iVertex=0;
for(int iParticle=0; iParticle < MAX_PARTICLES; iParticle++) {
m_randomParticleVertexData[iVertex].vertex.x = (float)(arc4random() % 2000) / 1000.0f - 1.0f;
m_randomParticleVertexData[iVertex].vertex.y = (float)(arc4random() % 2000) / 1000.0f - 1.0f;
m_randomParticleVertexData[iVertex].vertex.z = (float)(arc4random() % 2000) / 1000.0f - 1.0f;
m_randomParticleVertexData[iVertex].uva.u = 0.0f;
m_randomParticleVertexData[iVertex].uva.v = 0.0f;
iVertex++;
m_randomParticleVertexData[iVertex].vertex.x = m_randomParticleVertexData[iVertex-1].vertex.x;
m_randomParticleVertexData[iVertex].vertex.y = m_randomParticleVertexData[iVertex-1].vertex.y;
m_randomParticleVertexData[iVertex].vertex.z = m_randomParticleVertexData[iVertex-1].vertex.z;
m_randomParticleVertexData[iVertex].uva.u = 1.0f;
m_randomParticleVertexData[iVertex].uva.v = 0.0f;
for(int iParticle=0; iParticle < KRENGINE_MAX_RANDOM_PARTICLES; iParticle++) {
m_randomParticleVertexData[iVertex].vertex.x = (float)(arc4random() % 2000) / 1000.0f - 1000.0f;
m_randomParticleVertexData[iVertex].vertex.y = (float)(arc4random() % 2000) / 1000.0f - 1000.0f;
m_randomParticleVertexData[iVertex].vertex.z = (float)(arc4random() % 2000) / 1000.0f - 1000.0f;
m_randomParticleVertexData[iVertex].uva.u = -0.5f;
m_randomParticleVertexData[iVertex].uva.v = -inscribed_circle_radius;
iVertex++;
m_randomParticleVertexData[iVertex].vertex.x = m_randomParticleVertexData[iVertex-1].vertex.x;
m_randomParticleVertexData[iVertex].vertex.y = m_randomParticleVertexData[iVertex-1].vertex.y;
m_randomParticleVertexData[iVertex].vertex.z = m_randomParticleVertexData[iVertex-1].vertex.z;
m_randomParticleVertexData[iVertex].uva.u = 0.5f;
m_randomParticleVertexData[iVertex].uva.v = 1.0f;
m_randomParticleVertexData[iVertex].uva.v = -inscribed_circle_radius;
iVertex++;
m_randomParticleVertexData[iVertex].vertex.x = m_randomParticleVertexData[iVertex-1].vertex.x;
m_randomParticleVertexData[iVertex].vertex.y = m_randomParticleVertexData[iVertex-1].vertex.y;
m_randomParticleVertexData[iVertex].vertex.z = m_randomParticleVertexData[iVertex-1].vertex.z;
m_randomParticleVertexData[iVertex].uva.u = 0.0f;
m_randomParticleVertexData[iVertex].uva.v = -inscribed_circle_radius + equilateral_triangle_height;
iVertex++;
}
}

View File

@@ -45,7 +45,8 @@ using std::map;
class KRModelManager : public KRContextObject {
public:
static const int MAX_VOLUMETRIC_PLANES=500;
static const int KRENGINE_MAX_VOLUMETRIC_PLANES=500;
static const int KRENGINE_MAX_RANDOM_PARTICLES=150000;
KRModelManager(KRContext &context);
virtual ~KRModelManager();

View File

@@ -180,6 +180,7 @@ KRShader::KRShader(KRContext &context, char *szKey, std::string options, std::st
GLDEBUG(m_uniforms[KRENGINE_UNIFORM_GBUFFER_DEPTH] = glGetUniformLocation(m_iProgram, "gbuffer_depth"));
GLDEBUG(m_uniforms[KRENGINE_UNIFORM_DEPTH_FRAME] = glGetUniformLocation(m_iProgram, "depthFrame"));
GLDEBUG(m_uniforms[KRENGINE_UNIFORM_RENDER_FRAME] = glGetUniformLocation(m_iProgram, "renderFrame"));
GLDEBUG(m_uniforms[KRENGINE_UNIFORM_ABSOLUTE_TIME] = glGetUniformLocation(m_iProgram, "time_absolute"));
GLDEBUG(m_uniforms[KRENGINE_UNIFORM_SLICE_DEPTH_SCALE] = glGetUniformLocation(m_iProgram, "slice_depth_scale"));
GLDEBUG(m_uniforms[KRENGINE_UNIFORM_VOLUMETRIC_ENVIRONMENT_FRAME] = glGetUniformLocation(m_iProgram, "volumetricEnvironmentFrame"));
@@ -192,6 +193,9 @@ KRShader::KRShader(KRContext &context, char *szKey, std::string options, std::st
GLDEBUG(m_uniforms[KRENGINE_UNIFORM_FOG_SCALE] = glGetUniformLocation(m_iProgram, "fog_scale"));
GLDEBUG(m_uniforms[KRENGINE_UNIFORM_DENSITY_PREMULTIPLIED_EXPONENTIAL] = glGetUniformLocation(m_iProgram, "fog_density_premultiplied_exponential"));
GLDEBUG(m_uniforms[KRENGINE_UNIFORM_DENSITY_PREMULTIPLIED_SQUARED] = glGetUniformLocation(m_iProgram, "fog_density_premultiplied_squared"));
GLDEBUG(m_uniforms[KRENGINE_UNIFORM_PARTICLE_ORIGIN] = glGetUniformLocation(m_iProgram, "particle_origin"));
}
@@ -233,8 +237,12 @@ bool KRShader::bind(KRCamera &camera, const KRViewport &viewport, const KRMat4 &
return false;
}
GLDEBUG(glUseProgram(m_iProgram));
GLDEBUG(glUniform1f(m_uniforms[KRENGINE_UNIFORM_ABSOLUTE_TIME], getContext().getAbsoluteTime()));
int light_directional_count = 0;
int light_point_count = 0;
int light_spot_count = 0;

View File

@@ -128,6 +128,7 @@ public:
KRENGINE_UNIFORM_DEPTH_FRAME,
KRENGINE_UNIFORM_VOLUMETRIC_ENVIRONMENT_FRAME,
KRENGINE_UNIFORM_RENDER_FRAME,
KRENGINE_UNIFORM_ABSOLUTE_TIME,
KRENGINE_UNIFORM_FOG_NEAR,
KRENGINE_UNIFORM_FOG_FAR,
@@ -140,6 +141,8 @@ public:
KRENGINE_UNIFORM_SLICE_DEPTH_SCALE,
KRENGINE_UNIFORM_PARTICLE_ORIGIN,
KRENGINE_NUM_UNIFORMS
};
GLint m_uniforms[KRENGINE_NUM_UNIFORMS];

View File

@@ -29,10 +29,20 @@
// or implied, of Kearwood Gilbert.
//
#extension GL_EXT_shadow_samplers : require
varying mediump vec2 texCoord;
uniform sampler2D diffuseTexture;
varying mediump vec4 shadowMapCoord1;
uniform sampler2DShadow shadowTexture1;
uniform mediump vec3 light_color;
varying lowp float intensity_modulate;
void main() {
gl_FragColor = vec4(vec3(texture2D(diffuseTexture, texCoord)), 1.0);
//gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
//gl_FragColor = vec4(vec3(texture2D(diffuseTexture, texCoord)), 1.0);
// gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
gl_FragColor = vec4(light_color, 1.0) * shadow2DProjEXT(shadowTexture1, shadowMapCoord1) * max(1.0 - texCoord.x*texCoord.x-texCoord.y*texCoord.y, 0.0) * intensity_modulate;
// gl_FragColor.rgb = shadowMapCoord1.xyz / shadowMapCoord1.w;
// gl_FragColor.a = 1.0;
// gl_FragColor.b = 1.0;
}

View File

@@ -34,10 +34,25 @@ uniform highp mat4 mvp_matrix; // mvp_matrix is the result of multiplying t
uniform mediump vec4 viewport;
uniform mediump float flare_size;
attribute vec4 vertex_position;
uniform highp vec3 particle_origin;
varying mediump vec2 texCoord;
uniform highp mat4 shadow_mvp1;
varying mediump vec4 shadowMapCoord1;
varying mediump vec2 texCoord;
uniform highp float time_absolute;
varying lowp float intensity_modulate;
void main() {
texCoord = vertex_uv;
gl_Position = mvp_matrix * vertex_position + vec4(vertex_uv.x * viewport.w / viewport.z * 2.0 - 1.0, vertex_uv.y * 2.0 - 1.0, 0.0, 0.0) * flare_size;
// highp vec4 particle_center = mvp_matrix * (mod(vertex_position - vec4(particle_origin, 0.0), 2.0) - 1.0);
highp vec4 offset_center = vertex_position + vec4(particle_origin, 0.0);
offset_center.xyz += vec3(sin((time_absolute + vertex_position.x * 100.0) * 0.05), sin((time_absolute + vertex_position.y * 100.0) * 0.07), sin((time_absolute + vertex_position.z * 100.0) * 0.03)) * 0.05;
offset_center = vec4(mod(offset_center.x + 1.0, 2.0) - 1.0, mod(offset_center.y + 1.0, 2.0) - 1.0, mod(offset_center.z + 1.0, 2.0) - 1.0, 1.0);
highp vec4 particle_center = mvp_matrix * offset_center;
texCoord = vertex_uv * 3.46410161513775; // 3.46410161513775 = 2 * sqrt(3); 1 / (2 * sqrt(3)) is the radius of a circle encompased by a equilateral triangle with a side length of 1.
gl_Position = particle_center + vec4(vertex_uv.x * viewport.w / viewport.z * 2.0 - 1.0, vertex_uv.y * 2.0 - 1.0, 0.0, 0.0) * flare_size;
shadowMapCoord1 = shadow_mvp1 * offset_center;
intensity_modulate = sin(time_absolute + mod(vertex_position.x * 100.0, 6.28318530717959)) * 0.5 + 0.5;
}

View File

@@ -30,7 +30,7 @@ uniform highp mat4 inv_mvp_matrix;
uniform highp vec2 slice_depth_scale; // First component is the depth for the nearest plane, in view space. Second component is the distance between planes, in view space
uniform highp mat4 shadow_mvp1;
uniform highp mat4 shadow_mvp1;
varying mediump vec4 shadowMapCoord1;
uniform highp mat4 projection_matrix;