Lights: improve bandwidth usage
It should improve performance a lot, but it handles at most 32 simultaneous lights on screen. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@14800 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
508d866a2b
commit
4d0b9236b2
@ -1,12 +1,13 @@
|
||||
uniform sampler2D ntex;
|
||||
|
||||
uniform vec3 center;
|
||||
uniform vec3 col;
|
||||
uniform float r;
|
||||
uniform vec4 center[32];
|
||||
uniform vec4 col[32];
|
||||
uniform float energy[32];
|
||||
uniform int lightcount;
|
||||
uniform float spec;
|
||||
uniform vec2 screen;
|
||||
uniform mat4 invproj;
|
||||
uniform float energy;
|
||||
uniform mat4 viewm;
|
||||
|
||||
void main() {
|
||||
vec2 texc = gl_FragCoord.xy / screen;
|
||||
@ -16,21 +17,31 @@ void main() {
|
||||
xpos = invproj * xpos;
|
||||
xpos /= xpos.w;
|
||||
|
||||
float d = distance(center, xpos.xyz);
|
||||
float att = energy * 200.0 / (4. * 3.14 * d * d);
|
||||
vec3 diffuse = vec3(0.), specular = vec3(0.);
|
||||
|
||||
for (int i = 0; i < lightcount; ++i) {
|
||||
vec4 pseudocenter = viewm * vec4(center[i].xyz, 1.0);
|
||||
pseudocenter /= pseudocenter.w;
|
||||
vec3 light_pos = pseudocenter.xyz;
|
||||
vec3 light_col = col[i].xyz;
|
||||
float d = distance(light_pos, xpos.xyz);
|
||||
float att = energy[i] * 200. / (4. * 3.14 * d * d);
|
||||
|
||||
vec3 norm = texture2D(ntex, texc).xyz;
|
||||
norm = (norm - 0.5) * 2.0;
|
||||
|
||||
// Light Direction
|
||||
vec3 L = normalize(xpos.xyz - center);
|
||||
vec3 L = normalize(xpos.xyz - light_pos);
|
||||
|
||||
float NdotL = max(0.0, dot(norm, -L));
|
||||
diffuse += NdotL * light_col * att;
|
||||
// Reflected light dir
|
||||
vec3 R = reflect(-L, norm);
|
||||
float RdotE = max(0.0, dot(R, normalize(xpos.xyz)));
|
||||
float Specular = pow(RdotE, spec);
|
||||
|
||||
gl_FragData[0] = vec4(NdotL * col * att, 1.);
|
||||
gl_FragData[1] = vec4(Specular * col * att, 1.);
|
||||
specular += Specular * light_col * att;
|
||||
}
|
||||
|
||||
gl_FragData[0] = vec4(diffuse, 1.);
|
||||
gl_FragData[1] = vec4(specular , 1.);
|
||||
}
|
||||
|
@ -356,13 +356,15 @@ void LightBlendProvider::OnSetConstants(IMaterialRendererServices *srv, int)
|
||||
|
||||
void PointLightProvider::OnSetConstants(IMaterialRendererServices *srv, int)
|
||||
{
|
||||
int lightcount = m_color.size() / 4;
|
||||
srv->setVertexShaderConstant("screen", m_screen, 2);
|
||||
srv->setVertexShaderConstant("spec", &m_specular, 1);
|
||||
srv->setVertexShaderConstant("col", m_color, 3);
|
||||
srv->setVertexShaderConstant("center", m_pos, 3);
|
||||
srv->setVertexShaderConstant("r", &m_radius, 1);
|
||||
srv->setVertexShaderConstant("invproj", m_invproj.pointer(), 16);
|
||||
srv->setVertexShaderConstant("energy", &m_energy, 1);
|
||||
srv->setVertexShaderConstant("energy[0]", m_energy.data(), m_energy.size());
|
||||
srv->setVertexShaderConstant("col[0]", m_color.data(), m_color.size());
|
||||
srv->setVertexShaderConstant("center[0]", m_pos.data(), m_pos.size());
|
||||
srv->setVertexShaderConstant("viewm", m_view.pointer(), 16);
|
||||
srv->setVertexShaderConstant("lightcount", &lightcount, 1);
|
||||
|
||||
if (!firstdone)
|
||||
{
|
||||
|
@ -384,30 +384,15 @@ public:
|
||||
|
||||
virtual void OnSetConstants(video::IMaterialRendererServices *srv, int);
|
||||
|
||||
void setColor(float r, float g, float b)
|
||||
void setColor(const std::vector<float> &col)
|
||||
{
|
||||
m_color[0] = r;
|
||||
m_color[1] = g;
|
||||
m_color[2] = b;
|
||||
m_color = col;
|
||||
}
|
||||
|
||||
void setPosition(float x, float y, float z)
|
||||
void setPosition(const std::vector<float> &pos)
|
||||
{
|
||||
const video::IVideoDriver * const drv = irr_driver->getVideoDriver();
|
||||
|
||||
// get position in eye space coordinates
|
||||
core::matrix4 m_view = drv->getTransform(video::ETS_VIEW);
|
||||
float *mat = m_view.pointer();
|
||||
|
||||
float scale = mat[3] * x + mat[7] * y + mat[11] * z + mat[15];
|
||||
m_pos[0] = (mat[0] * x + mat[4] * y + mat[8] * z + mat[12]) / scale;
|
||||
m_pos[1] = (mat[1] * x + mat[5] * y + mat[9] * z + mat[13]) / scale;
|
||||
m_pos[2] = (mat[2] * x + mat[6] * y + mat[10] * z + mat[14]) / scale;
|
||||
}
|
||||
|
||||
void setRadius(float r)
|
||||
{
|
||||
m_radius = r;
|
||||
m_pos = pos;
|
||||
return;
|
||||
}
|
||||
|
||||
void setSpecular(float s)
|
||||
@ -415,27 +400,26 @@ public:
|
||||
m_specular = s;
|
||||
}
|
||||
|
||||
void setEnergy(float e) {
|
||||
void setEnergy(const std::vector<float> &e) {
|
||||
m_energy = e;
|
||||
}
|
||||
|
||||
void updateIPVMatrix()
|
||||
{
|
||||
const video::IVideoDriver * const drv = irr_driver->getVideoDriver();
|
||||
|
||||
m_view = drv->getTransform(video::ETS_VIEW);
|
||||
m_invproj = drv->getTransform(video::ETS_PROJECTION);
|
||||
m_invproj.makeInverse();
|
||||
}
|
||||
|
||||
private:
|
||||
core::matrix4 m_invproj;
|
||||
core::matrix4 m_invproj, m_view;
|
||||
|
||||
float m_color[3];
|
||||
float m_pos[3];
|
||||
std::vector<float> m_color;
|
||||
std::vector<float> m_pos;
|
||||
std::vector<float> m_energy;
|
||||
float m_screen[2];
|
||||
float m_radius;
|
||||
float m_specular;
|
||||
float m_energy;
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -31,15 +31,31 @@ using namespace video;
|
||||
using namespace scene;
|
||||
using namespace core;
|
||||
|
||||
IMesh * LightNode::sphere = NULL;
|
||||
SMaterial LightNode::mat;
|
||||
aabbox3df LightNode::box;
|
||||
|
||||
|
||||
LightNode::LightNode(scene::ISceneManager* mgr, float radius, float e, float r, float g, float b):
|
||||
ISceneNode(mgr->getRootSceneNode(), mgr, -1)
|
||||
{
|
||||
sq = new ScreenQuad(irr_driver->getVideoDriver());
|
||||
energy = e;
|
||||
m_color[0] = r;
|
||||
m_color[1] = g;
|
||||
m_color[2] = b;
|
||||
}
|
||||
|
||||
LightNode::~LightNode()
|
||||
{
|
||||
}
|
||||
|
||||
void LightNode::render()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void LightNode::renderLightSet(const std::vector<float> &positions, const std::vector<float> &colors, const std::vector<float> &energy)
|
||||
{
|
||||
assert (colors.size() == positions.size() && positions.size() == (energy.size() * 4));
|
||||
ScreenQuad *sq = new ScreenQuad(irr_driver->getVideoDriver());
|
||||
SMaterial &mat = sq->getMaterial();
|
||||
|
||||
mat.Lighting = false;
|
||||
@ -59,28 +75,9 @@ LightNode::LightNode(scene::ISceneManager* mgr, float radius, float e, float r,
|
||||
mat.MaterialTypeParam = pack_textureBlendFunc(EBF_ONE, EBF_ONE);
|
||||
mat.BlendOperation = EBO_ADD;
|
||||
|
||||
sphere = mgr->getGeometryCreator()->createSphereMesh(1, 16, 16);
|
||||
box = sphere->getBoundingBox();
|
||||
|
||||
setScale(vector3df(radius));
|
||||
m_radius = radius;
|
||||
energy = e;
|
||||
|
||||
m_color[0] = r;
|
||||
m_color[1] = g;
|
||||
m_color[2] = b;
|
||||
}
|
||||
|
||||
LightNode::~LightNode()
|
||||
{
|
||||
}
|
||||
|
||||
void LightNode::render()
|
||||
{
|
||||
PointLightProvider * const cb = (PointLightProvider *) irr_driver->getCallback(ES_POINTLIGHT);
|
||||
cb->setColor(m_color[0], m_color[1], m_color[2]);
|
||||
cb->setPosition(getPosition().X, getPosition().Y, getPosition().Z);
|
||||
cb->setRadius(m_radius);
|
||||
cb->setColor(colors);
|
||||
cb->setPosition(positions);
|
||||
cb->setEnergy(energy);
|
||||
// Irrlicht's ScreenQuad reset the matrixes, we need to keep them
|
||||
IVideoDriver * const drv = irr_driver->getVideoDriver();
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include <ISceneNode.h>
|
||||
#include <utils/cpp2011.h>
|
||||
#include <vector>
|
||||
|
||||
using namespace irr;
|
||||
|
||||
@ -37,6 +38,7 @@ public:
|
||||
virtual ~LightNode();
|
||||
|
||||
virtual void render() OVERRIDE;
|
||||
static void renderLightSet(const std::vector<float> &positions, const std::vector<float> &colors, const std::vector<float> &energy);
|
||||
|
||||
virtual const core::aabbox3d<f32>& getBoundingBox() const OVERRIDE
|
||||
{
|
||||
@ -46,17 +48,15 @@ public:
|
||||
virtual void OnRegisterSceneNode() OVERRIDE;
|
||||
|
||||
virtual u32 getMaterialCount() const OVERRIDE { return 1; }
|
||||
virtual video::SMaterial& getMaterial(u32 i) OVERRIDE { return mat; }
|
||||
virtual bool isCullable() { return true; }
|
||||
virtual bool isPointLight() { return true; }
|
||||
|
||||
float getRadius() const { return m_radius; }
|
||||
void getColor(float out[3]) const { memcpy(out, m_color, 3 * sizeof(float)); }
|
||||
float getEnergy() const { return energy; }
|
||||
core::vector3df getColor() const { return core::vector3df(m_color[0], m_color[1], m_color[2]); }
|
||||
|
||||
protected:
|
||||
static video::SMaterial mat;
|
||||
static core::aabbox3df box;
|
||||
|
||||
static scene::IMesh *sphere;
|
||||
class ScreenQuad *sq;
|
||||
|
||||
float m_radius;
|
||||
|
@ -703,13 +703,22 @@ void IrrDriver::renderLights(const core::aabbox3df& cambox,
|
||||
const core::vector3df &camdir = (camnode->getTarget() - camcenter).normalize();
|
||||
|
||||
float fov = camnode->getFOV() / 2.;
|
||||
std::vector<float> accumulatedLightPos;
|
||||
std::vector<float> accumulatedLightColor;
|
||||
std::vector<float> accumulatedLightEnergy;
|
||||
unsigned lightnum = 0;
|
||||
for (unsigned int i = 0; i < lightcount; i++)
|
||||
{
|
||||
if (!m_lights[i]->isPointLight()) {
|
||||
m_lights[i]->render();
|
||||
continue;
|
||||
}
|
||||
if (lightnum >= 32)
|
||||
continue;
|
||||
// Light culling
|
||||
const core::vector3df &lightpos = (m_lights[i]->getPosition() - camcenter);
|
||||
float light_radius = m_lights[i]->getRadius();
|
||||
float dotprod = camdir.dotProduct(lightpos);
|
||||
if (m_lights[i]->isCullable()) {
|
||||
if (dotprod > 0.) {
|
||||
// Pixels in front of camera
|
||||
// Are they too far ?
|
||||
@ -721,9 +730,20 @@ void IrrDriver::renderLights(const core::aabbox3df& cambox,
|
||||
continue;
|
||||
} else if (lightpos.getLength() > light_radius)
|
||||
continue;
|
||||
}
|
||||
m_lights[i]->render();
|
||||
const core::vector3df &pos = m_lights[i]->getPosition();
|
||||
accumulatedLightPos.push_back(pos.X);
|
||||
accumulatedLightPos.push_back(pos.Y);
|
||||
accumulatedLightPos.push_back(pos.Z);
|
||||
accumulatedLightPos.push_back(0.);
|
||||
const core::vector3df &col = m_lights[i]->getColor();
|
||||
accumulatedLightColor.push_back(col.X);
|
||||
accumulatedLightColor.push_back(col.Y);
|
||||
accumulatedLightColor.push_back(col.Z);
|
||||
accumulatedLightColor.push_back(0.);
|
||||
accumulatedLightEnergy.push_back(m_lights[i]->getEnergy());
|
||||
lightnum++;
|
||||
} // for i in lights
|
||||
LightNode::renderLightSet(accumulatedLightPos, accumulatedLightColor, accumulatedLightEnergy);
|
||||
// Handle SSAO
|
||||
SMaterial m_material;
|
||||
GaussianBlurProvider * const gacb = (GaussianBlurProvider *) irr_driver->
|
||||
|
@ -32,7 +32,7 @@ public:
|
||||
virtual ~SunNode();
|
||||
|
||||
virtual void render() OVERRIDE;
|
||||
virtual bool isCullable() { return false; }
|
||||
virtual bool isPointLight() OVERRIDE { return false; }
|
||||
|
||||
private:
|
||||
ScreenQuad *sq;
|
||||
|
Loading…
Reference in New Issue
Block a user