Factorize transparent materials too

This commit is contained in:
Vincent Lejeune 2014-07-11 20:10:21 +02:00
parent ebc0d956d4
commit 3a4cc63602
7 changed files with 125 additions and 181 deletions

View File

@ -709,116 +709,27 @@ void IrrDriver::renderTransparent()
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glDisable(GL_CULL_FACE);
TransparentMeshes<TM_DEFAULT>::reset();
TransparentMeshes<TM_ADDITIVE>::reset();
ListBlendTransparent::Arguments.clear();
ListAdditiveTransparent::Arguments.clear();
ListBlendTransparentFog::Arguments.clear();
ListAdditiveTransparentFog::Arguments.clear();
m_scene_manager->drawAll(scene::ESNRP_TRANSPARENT);
glBindVertexArray(getVAO(EVT_STANDARD));
if (World::getWorld() && World::getWorld()->isFogEnabled())
{
const Track * const track = World::getWorld()->getTrack();
// This function is only called once per frame - thus no need for setters.
const float fogmax = track->getFogMax();
const float startH = track->getFogStartHeight();
const float endH = track->getFogEndHeight();
const float start = track->getFogStart();
const float end = track->getFogEnd();
const video::SColor tmpcol = track->getFogColor();
core::vector3df col(tmpcol.getRed() / 255.0f,
tmpcol.getGreen() / 255.0f,
tmpcol.getBlue() / 255.0f);
glUseProgram(MeshShader::TransparentFogShader::Program);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
for (unsigned i = 0; i < TransparentMeshes<TM_DEFAULT>::MeshSet.size(); i++)
{
GLMesh &mesh = *TransparentMeshes<TM_DEFAULT>::MeshSet[i];
if (mesh.VAOType != EVT_STANDARD)
{
#ifdef DEBUG
Log::error("Materials", "Wrong vertex Type associed to fog + transparent blend (hint texture : %s)", mesh.textures[0]->getName().getPath().c_str());
#endif
glBindVertexArray(getVAO(mesh.VAOType));
}
if (!mesh.textures[0])
mesh.textures[0] = getUnicolorTexture(video::SColor(255, 255, 255, 255));
compressTexture(mesh.textures[0], true);
setTexture(0, getTextureGLuint(mesh.textures[0]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true);
draw<MeshShader::TransparentFogShader>(&mesh, TransparentMeshes<TM_DEFAULT>::MVPSet[i], TransparentMeshes<TM_DEFAULT>::MeshSet[i]->TextureMatrix, fogmax, startH, endH, start, end, col, Camera::getCamera(0)->getCameraSceneNode()->getAbsolutePosition(), 0);
if (mesh.VAOType != EVT_STANDARD)
glBindVertexArray(getVAO(EVT_STANDARD));
}
renderMeshes2ndPass<MeshShader::TransparentFogShader, video::EVT_STANDARD>({ MeshShader::TransparentFogShader::TU_tex }, ListBlendTransparentFog::Arguments);
glBlendFunc(GL_ONE, GL_ONE);
for (unsigned i = 0; i < TransparentMeshes<TM_ADDITIVE>::MeshSet.size(); i++)
{
GLMesh &mesh = *TransparentMeshes<TM_ADDITIVE>::MeshSet[i];
if (mesh.VAOType != EVT_STANDARD)
{
#ifdef DEBUG
Log::error("Materials", "Wrong vertex Type associed to fog + transparent additive (hint texture : %s)", mesh.textures[0]->getName().getPath().c_str());
#endif
glBindVertexArray(getVAO(mesh.VAOType));
}
glBindVertexArray(getVAO(mesh.VAOType));
if (!mesh.textures[0])
mesh.textures[0] = getUnicolorTexture(video::SColor(255, 255, 255, 255));
compressTexture(mesh.textures[0], true);
setTexture(0, getTextureGLuint(mesh.textures[0]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true);
draw<MeshShader::TransparentFogShader>(&mesh, TransparentMeshes<TM_ADDITIVE>::MVPSet[i], TransparentMeshes<TM_ADDITIVE>::MeshSet[i]->TextureMatrix, fogmax, startH, endH, start, end, col, Camera::getCamera(0)->getCameraSceneNode()->getAbsolutePosition(), 0);
if (mesh.VAOType != EVT_STANDARD)
glBindVertexArray(getVAO(EVT_STANDARD));
}
renderMeshes2ndPass<MeshShader::TransparentFogShader, video::EVT_STANDARD>({ MeshShader::TransparentFogShader::TU_tex }, ListAdditiveTransparentFog::Arguments);
}
else
{
glUseProgram(MeshShader::TransparentShader::Program);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
for (unsigned i = 0; i < TransparentMeshes<TM_DEFAULT>::MeshSet.size(); i++)
{
GLMesh &mesh = *TransparentMeshes<TM_DEFAULT>::MeshSet[i];
if (mesh.VAOType != EVT_STANDARD)
{
#ifdef DEBUG
Log::error("Materials", "Wrong vertex Type associed to fog + transparent additive (hint texture : %s)", mesh.textures[0]->getName().getPath().c_str());
#endif
glBindVertexArray(getVAO(mesh.VAOType));
}
glBindVertexArray(getVAO(mesh.VAOType));
if (!mesh.textures[0])
mesh.textures[0] = getUnicolorTexture(video::SColor(255, 255, 255, 255));
compressTexture(mesh.textures[0], true);
setTexture(0, getTextureGLuint(mesh.textures[0]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true);
draw<MeshShader::TransparentShader>(&mesh, TransparentMeshes<TM_DEFAULT>::MVPSet[i], TransparentMeshes<TM_DEFAULT>::MeshSet[i]->TextureMatrix, 0);
if (mesh.VAOType != EVT_STANDARD)
glBindVertexArray(getVAO(EVT_STANDARD));
}
renderMeshes2ndPass<MeshShader::TransparentShader, video::EVT_STANDARD>({ MeshShader::TransparentShader::TU_tex }, ListBlendTransparent::Arguments);
glBlendFunc(GL_ONE, GL_ONE);
for (unsigned i = 0; i < TransparentMeshes<TM_ADDITIVE>::MeshSet.size(); i++)
{
GLMesh &mesh = *TransparentMeshes<TM_ADDITIVE>::MeshSet[i];
if (mesh.VAOType != EVT_STANDARD)
{
#ifdef DEBUG
Log::error("Materials", "Wrong vertex Type associed to fog + transparent additive (hint texture : %s)", mesh.textures[0]->getName().getPath().c_str());
#endif
glBindVertexArray(getVAO(mesh.VAOType));
}
glBindVertexArray(getVAO(mesh.VAOType));
compressTexture(mesh.textures[0], true);
setTexture(0, getTextureGLuint(mesh.textures[0]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true);
draw<MeshShader::TransparentShader>(&mesh, TransparentMeshes<TM_ADDITIVE>::MVPSet[i], TransparentMeshes<TM_ADDITIVE>::MeshSet[i]->TextureMatrix, 0);
if (mesh.VAOType != EVT_STANDARD)
glBindVertexArray(getVAO(EVT_STANDARD));
}
renderMeshes2ndPass<MeshShader::TransparentShader, video::EVT_STANDARD>({ MeshShader::TransparentShader::TU_tex }, ListAdditiveTransparent::Arguments);
}
}

View File

@ -1153,7 +1153,7 @@ namespace MeshShader
GLuint TransparentShader::Program;
GLuint TransparentShader::uniform_MVP;
GLuint TransparentShader::uniform_TM;
GLuint TransparentShader::uniform_tex;
GLuint TransparentShader::TU_tex;
void TransparentShader::init()
{
@ -1162,25 +1162,29 @@ namespace MeshShader
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/transparent.frag").c_str());
uniform_MVP = glGetUniformLocation(Program, "ModelMatrix");
uniform_TM = glGetUniformLocation(Program, "TextureMatrix");
uniform_tex = glGetUniformLocation(Program, "tex");
GLuint uniform_tex = glGetUniformLocation(Program, "tex");
if (!UserConfigParams::m_ubo_disabled)
{
GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData");
glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0);
}
TU_tex = 0;
glUseProgram(Program);
glUniform1i(uniform_tex, TU_tex);
glUseProgram(0);
}
void TransparentShader::setUniforms(const core::matrix4 &ModelMatrix, const core::matrix4 &TextureMatrix, unsigned TU_tex)
void TransparentShader::setUniforms(const core::matrix4 &ModelMatrix, const core::matrix4 &TextureMatrix)
{
glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelMatrix.pointer());
glUniformMatrix4fv(uniform_TM, 1, GL_FALSE, TextureMatrix.pointer());
glUniform1i(uniform_tex, TU_tex);
}
GLuint TransparentFogShader::Program;
GLuint TransparentFogShader::uniform_MVP;
GLuint TransparentFogShader::uniform_TM;
GLuint TransparentFogShader::uniform_tex;
GLuint TransparentFogShader::TU_tex;
GLuint TransparentFogShader::uniform_fogmax;
GLuint TransparentFogShader::uniform_startH;
GLuint TransparentFogShader::uniform_endH;
@ -1195,7 +1199,7 @@ namespace MeshShader
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/transparentfog.frag").c_str());
uniform_MVP = glGetUniformLocation(Program, "ModelMatrix");
uniform_TM = glGetUniformLocation(Program, "TextureMatrix");
uniform_tex = glGetUniformLocation(Program, "tex");
GLuint uniform_tex = glGetUniformLocation(Program, "tex");
uniform_fogmax = glGetUniformLocation(Program, "fogmax");
uniform_startH = glGetUniformLocation(Program, "startH");
uniform_endH = glGetUniformLocation(Program, "endH");
@ -1207,9 +1211,14 @@ namespace MeshShader
GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData");
glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0);
}
TU_tex = 0;
glUseProgram(Program);
glUniform1i(uniform_tex, TU_tex);
glUseProgram(0);
}
void TransparentFogShader::setUniforms(const core::matrix4 &ModelMatrix, const core::matrix4 &TextureMatrix, float fogmax, float startH, float endH, float start, float end, const core::vector3df &col, const core::vector3df &campos, unsigned TU_tex)
void TransparentFogShader::setUniforms(const core::matrix4 &ModelMatrix, const core::matrix4 &TextureMatrix, float fogmax, float startH, float endH, float start, float end, const core::vector3df &col, const core::vector3df &campos)
{
glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelMatrix.pointer());
glUniformMatrix4fv(uniform_TM, 1, GL_FALSE, TextureMatrix.pointer());
@ -1219,7 +1228,6 @@ namespace MeshShader
glUniform1f(uniform_start, start);
glUniform1f(uniform_end, end);
glUniform3f(uniform_col, col.X, col.Y, col.Z);
glUniform1i(uniform_tex, TU_tex);
}
GLuint BillboardShader::Program;

View File

@ -253,20 +253,22 @@ class TransparentShader
{
public:
static GLuint Program;
static GLuint uniform_MVP, uniform_TM, uniform_tex;
static GLuint uniform_MVP, uniform_TM;
static GLuint TU_tex;
static void init();
static void setUniforms(const core::matrix4 &ModelMatrix, const core::matrix4 &TextureMatrix, unsigned TU_tex);
static void setUniforms(const core::matrix4 &ModelMatrix, const core::matrix4 &TextureMatrix);
};
class TransparentFogShader
{
public:
static GLuint Program;
static GLuint uniform_MVP, uniform_TM, uniform_tex, uniform_fogmax, uniform_startH, uniform_endH, uniform_start, uniform_end, uniform_col;
static GLuint uniform_MVP, uniform_TM, uniform_fogmax, uniform_startH, uniform_endH, uniform_start, uniform_end, uniform_col;
static GLuint TU_tex;
static void init();
static void setUniforms(const core::matrix4 &ModelMatrix, const core::matrix4 &TextureMatrix, float fogmax, float startH, float endH, float start, float end, const core::vector3df &col, const core::vector3df &campos, unsigned TU_tex);
static void setUniforms(const core::matrix4 &ModelMatrix, const core::matrix4 &TextureMatrix, float fogmax, float startH, float endH, float start, float end, const core::vector3df &col, const core::vector3df &campos);
};
class BillboardShader

View File

@ -6,6 +6,7 @@
#include "config/user_config.hpp"
#include "modes/world.hpp"
#include "tracks/track.hpp"
#include "graphics/camera.hpp"
#include "utils/profiler.hpp"
using namespace irr;
@ -200,16 +201,40 @@ void STKAnimatedMesh::render()
glUseProgram(MeshShader::BubbleShader::Program);
GLMesh* mesh;
for_in(mesh, TransparentMesh[TM_DEFAULT])
if (World::getWorld() && World::getWorld()->isFogEnabled())
{
TransparentMeshes<TM_DEFAULT>::MeshSet.push_back(mesh);
TransparentMeshes<TM_DEFAULT>::MVPSet.push_back(AbsoluteTransformation);
const Track * const track = World::getWorld()->getTrack();
// Todo : put everything in a ubo
const float fogmax = track->getFogMax();
const float startH = track->getFogStartHeight();
const float endH = track->getFogEndHeight();
const float start = track->getFogStart();
const float end = track->getFogEnd();
const video::SColor tmpcol = track->getFogColor();
core::vector3df col(tmpcol.getRed() / 255.0f,
tmpcol.getGreen() / 255.0f,
tmpcol.getBlue() / 255.0f);
for_in(mesh, TransparentMesh[TM_DEFAULT])
ListBlendTransparentFog::Arguments.push_back(
std::make_tuple(mesh, AbsoluteTransformation, mesh->TextureMatrix,
fogmax, startH, endH, start, end, col,
Camera::getCamera(0)->getCameraSceneNode()->getAbsolutePosition()));
for_in(mesh, TransparentMesh[TM_ADDITIVE])
ListAdditiveTransparentFog::Arguments.push_back(
std::make_tuple(mesh, AbsoluteTransformation, mesh->TextureMatrix,
fogmax, startH, endH, start, end, col,
Camera::getCamera(0)->getCameraSceneNode()->getAbsolutePosition()));
}
else
{
for_in(mesh, TransparentMesh[TM_DEFAULT])
ListBlendTransparent::Arguments.push_back(std::make_tuple(mesh, AbsoluteTransformation, mesh->TextureMatrix));
for_in(mesh, TransparentMesh[TM_ADDITIVE])
{
TransparentMeshes<TM_ADDITIVE>::MeshSet.push_back(mesh);
TransparentMeshes<TM_ADDITIVE>::MVPSet.push_back(AbsoluteTransformation);
ListAdditiveTransparent::Arguments.push_back(std::make_tuple(mesh, AbsoluteTransformation, mesh->TextureMatrix));
}
return;
}

View File

@ -379,58 +379,6 @@ void drawGrassPass2(const GLMesh &mesh, const core::matrix4 & ModelViewProjectio
glDrawElementsBaseVertex(ptype, count, itype, (GLvoid *)mesh.vaoOffset, mesh.vaoBaseVertex);
}
void drawTransparentObject(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix)
{
irr_driver->IncreaseObjectCount();
GLenum ptype = mesh.PrimitiveType;
GLenum itype = mesh.IndexType;
size_t count = mesh.IndexCount;
compressTexture(mesh.textures[0], true);
setTexture(0, getTextureGLuint(mesh.textures[0]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true);
MeshShader::TransparentShader::setUniforms(ModelViewProjectionMatrix, TextureMatrix, 0);
assert(mesh.vao);
glBindVertexArray(mesh.vao);
glDrawElements(ptype, count, itype, 0);
}
void drawTransparentFogObject(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix)
{
irr_driver->IncreaseObjectCount();
GLenum ptype = mesh.PrimitiveType;
GLenum itype = mesh.IndexType;
size_t count = mesh.IndexCount;
const Track * const track = World::getWorld()->getTrack();
// This function is only called once per frame - thus no need for setters.
const float fogmax = track->getFogMax();
const float startH = track->getFogStartHeight();
const float endH = track->getFogEndHeight();
const float start = track->getFogStart();
const float end = track->getFogEnd();
const video::SColor tmpcol = track->getFogColor();
core::vector3df col(tmpcol.getRed() / 255.0f,
tmpcol.getGreen() / 255.0f,
tmpcol.getBlue() / 255.0f);
if (mesh.textures[0] != NULL)
{
compressTexture(mesh.textures[0], true);
setTexture(0, getTextureGLuint(mesh.textures[0]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true);
}
glUseProgram(MeshShader::TransparentFogShader::Program);
MeshShader::TransparentFogShader::setUniforms(ModelViewProjectionMatrix, TextureMatrix, fogmax, startH, endH, start, end, col, Camera::getCamera(0)->getCameraSceneNode()->getAbsolutePosition(), 0);
assert(mesh.vao);
glBindVertexArray(mesh.vao);
glDrawElements(ptype, count, itype, 0);
}
void drawBubble(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix)
{
irr_driver->IncreaseObjectCount();
@ -525,3 +473,7 @@ std::vector<std::tuple<GLMesh *, core::matrix4, core::matrix4> > ListAlphaRefSM:
std::vector<std::tuple<GLMesh *, core::matrix4, core::matrix4, video::SColorf> > ListSphereMapSM::Arguments;
std::vector<std::tuple<GLMesh *, core::matrix4> > ListUnlitSM::Arguments;
std::vector<std::tuple<GLMesh *, core::matrix4> > ListDetailSM::Arguments;
std::vector<std::tuple<GLMesh *, core::matrix4, core::matrix4> > ListBlendTransparent::Arguments;
std::vector<std::tuple<GLMesh *, core::matrix4, core::matrix4> > ListAdditiveTransparent::Arguments;
std::vector<std::tuple<GLMesh *, core::matrix4, core::matrix4, float, float, float, float, float, core::vector3df, core::vector3df> > ListBlendTransparentFog::Arguments;
std::vector<std::tuple<GLMesh *, core::matrix4, core::matrix4, float, float, float, float, float, core::vector3df, core::vector3df> > ListAdditiveTransparentFog::Arguments;

View File

@ -145,6 +145,30 @@ public:
static std::vector<std::tuple<GLMesh *, core::matrix4> > Arguments;
};
class ListBlendTransparent
{
public:
static std::vector<std::tuple<GLMesh *, core::matrix4, core::matrix4> > Arguments;
};
class ListAdditiveTransparent
{
public:
static std::vector<std::tuple<GLMesh *, core::matrix4, core::matrix4> > Arguments;
};
class ListBlendTransparentFog
{
public:
static std::vector<std::tuple<GLMesh *, core::matrix4, core::matrix4, float, float, float, float, float, core::vector3df, core::vector3df> > Arguments;
};
class ListAdditiveTransparentFog
{
public:
static std::vector<std::tuple<GLMesh *, core::matrix4, core::matrix4, float, float, float, float, float, core::vector3df, core::vector3df> > Arguments;
};
template<enum ShadedMaterial T>
class GroupedSM
{
@ -194,8 +218,6 @@ template<enum TransparentMaterial T>
std::vector<core::matrix4> TransparentMeshes<T>::MVPSet;
// Forward pass (for transparents meshes)
void drawTransparentObject(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix);
void drawTransparentFogObject(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix);
void drawBubble(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix);
GeometricMaterial MaterialTypeToGeometricMaterial(video::E_MATERIAL_TYPE, video::E_VERTEX_TYPE);

View File

@ -431,7 +431,7 @@ void STKMeshSceneNode::render()
compressTexture(mesh.textures[0], true);
setTexture(0, getTextureGLuint(mesh.textures[0]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true);
MeshShader::TransparentFogShader::setUniforms(AbsoluteTransformation, mesh.TextureMatrix, fogmax, startH, endH, start, end, col, Camera::getCamera(0)->getCameraSceneNode()->getAbsolutePosition(), 0);
MeshShader::TransparentFogShader::setUniforms(AbsoluteTransformation, mesh.TextureMatrix, fogmax, startH, endH, start, end, col, Camera::getCamera(0)->getCameraSceneNode()->getAbsolutePosition());
assert(mesh.vao);
glBindVertexArray(mesh.vao);
@ -451,9 +451,9 @@ void STKMeshSceneNode::render()
size_t count = mesh.IndexCount;
compressTexture(mesh.textures[0], true);
setTexture(0, getTextureGLuint(mesh.textures[0]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true);
setTexture(MeshShader::TransparentShader::TU_tex, getTextureGLuint(mesh.textures[0]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true);
MeshShader::TransparentShader::setUniforms(AbsoluteTransformation, mesh.TextureMatrix, 0);
MeshShader::TransparentShader::setUniforms(AbsoluteTransformation, mesh.TextureMatrix);
assert(mesh.vao);
glBindVertexArray(mesh.vao);
glDrawElements(ptype, count, itype, 0);
@ -465,16 +465,40 @@ void STKMeshSceneNode::render()
GLMesh* mesh;
for_in(mesh, TransparentMesh[TM_DEFAULT])
if (World::getWorld() && World::getWorld()->isFogEnabled())
{
TransparentMeshes<TM_DEFAULT>::MeshSet.push_back(mesh);
TransparentMeshes<TM_DEFAULT>::MVPSet.push_back(AbsoluteTransformation);
const Track * const track = World::getWorld()->getTrack();
// Todo : put everything in a ubo
const float fogmax = track->getFogMax();
const float startH = track->getFogStartHeight();
const float endH = track->getFogEndHeight();
const float start = track->getFogStart();
const float end = track->getFogEnd();
const video::SColor tmpcol = track->getFogColor();
core::vector3df col(tmpcol.getRed() / 255.0f,
tmpcol.getGreen() / 255.0f,
tmpcol.getBlue() / 255.0f);
for_in(mesh, TransparentMesh[TM_DEFAULT])
ListBlendTransparentFog::Arguments.push_back(
std::make_tuple(mesh, AbsoluteTransformation, mesh->TextureMatrix,
fogmax, startH, endH, start, end, col,
Camera::getCamera(0)->getCameraSceneNode()->getAbsolutePosition()));
for_in(mesh, TransparentMesh[TM_ADDITIVE])
ListAdditiveTransparentFog::Arguments.push_back(
std::make_tuple(mesh, AbsoluteTransformation, mesh->TextureMatrix,
fogmax, startH, endH, start, end, col,
Camera::getCamera(0)->getCameraSceneNode()->getAbsolutePosition()));
}
else
{
for_in(mesh, TransparentMesh[TM_DEFAULT])
ListBlendTransparent::Arguments.push_back(std::make_tuple(mesh, AbsoluteTransformation, mesh->TextureMatrix));
for_in(mesh, TransparentMesh[TM_ADDITIVE])
{
TransparentMeshes<TM_ADDITIVE>::MeshSet.push_back(mesh);
TransparentMeshes<TM_ADDITIVE>::MVPSet.push_back(AbsoluteTransformation);
ListAdditiveTransparent::Arguments.push_back(std::make_tuple(mesh, AbsoluteTransformation, mesh->TextureMatrix));
}
if (!TransparentMesh[TM_BUBBLE].empty())