Sorry for bumping, but i just made an example which uses the suggested method to send
Code: Select all
core::matrix4 Matrix = driver->getTransform(ETS_TEXTURE_0);
as a uniform variable.
As you can see in the screenshot, only scaling works this way. (Bottom left cube is the shader one, bottom right is textured with the transformations applied, top cube is the plain texture without any transformation). 1 and 2 should look the same, but they don't!
http://imgur.com/a/yPE4A
Example code:
Code: Select all
#include <irrlicht.h>
const irr::core::stringc vertexShader =
"uniform mat4 matrix;\
void main(void)\
{\
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\
gl_TexCoord[0] = matrix*gl_MultiTexCoord0;\
}";
const irr::core::stringc fragmentShader =
"uniform sampler2D Texture;\
\
void main(void)\
{\
gl_FragColor = texture2D(Texture, gl_TexCoord[0].xy);\
}";
class MyShaderCallBack: public irr::video::IShaderConstantSetCallBack
{
public:
MyShaderCallBack() :
TextureID(-1), textureMatrixID(-1), FirstUpdate(true)
{
}
virtual void OnSetConstants(irr::video::IMaterialRendererServices* services,
irr::s32 userData)
{
//get shader constant id.
if (this->FirstUpdate)
{
this->TextureID = services->getPixelShaderConstantID("Texture");
this->textureMatrixID = services->getPixelShaderConstantID(
"matrix");
this->FirstUpdate = false;
}
//set texture
const irr::s32 TextureLayerID = 0;
services->setPixelShaderConstant(this->TextureID, &TextureLayerID, 1);
//set matrix;
const irr::core::matrix4& matrix =
services->getVideoDriver()->getTransform(
irr::video::ETS_TEXTURE_0);
services->setVertexShaderConstant(this->textureMatrixID,
matrix.pointer(), 16);
}
private:
irr::s32 TextureID;
irr::s32 textureMatrixID;
bool FirstUpdate;
};
/**
* Determines if a point is inside a circle.
*
* \param x The x coordinate of the point
* \param y The y coordinate of the point
* \param cx The x coordinate of the center of the circle
* \param cy The y coordinate of the center of the circle
* \param radius The radius of the circle
* \return True if point is inside circle
*/
bool isInCircle(const irr::u32 x, const irr::u32 y, const irr::u32 cx,
const irr::u32 cy, const irr::u32 radius)
{
const irr::u32 dx = x - cx;
const irr::u32 dy = y - cy;
const irr::u32 distance = dx * dx + dy * dy;
return distance < (radius * radius);
}
irr::video::IImage* createJapaneseFlagImage(irr::video::IVideoDriver* driver,
const irr::core::dimension2du& size = irr::core::dimension2du(512, 512),
const irr::video::SColor& foregroundColor = irr::video::SColor(255, 199,
0, 37), const irr::video::SColor& backgroundColor =
irr::video::SColor(255, 255, 255, 255))
{
static const unsigned int BITDEPTH = 4;
const unsigned int dataSize = size.Width * size.Height * BITDEPTH;
irr::u8 imageData[dataSize];
const irr::u32 centerX = size.Width / 2;
const irr::u32 centerY = size.Height / 2;
irr::u32 radius = 0;
if (centerX > centerY)
radius = size.Height - centerY;
else
radius = size.Width - centerX;
radius*=0.5f;
for (irr::u32 i = 0; i < dataSize; i += BITDEPTH)
{
const irr::u32 x = (i / BITDEPTH) % size.Width;
const irr::u32 y = i / (BITDEPTH * size.Width);
if (isInCircle(x, y, centerX, centerY, radius))
{
//point is in circle, so draw in foreground color
imageData[i] = foregroundColor.getBlue();
imageData[i + 1] = foregroundColor.getGreen();
imageData[i + 2] = foregroundColor.getRed();
imageData[i + 3] = foregroundColor.getAlpha();
}
else //draw background
{
imageData[i] = backgroundColor.getBlue();
imageData[i + 1] = backgroundColor.getGreen();
imageData[i + 2] = backgroundColor.getRed();
imageData[i + 3] = backgroundColor.getAlpha();
}
}
void* data = &imageData[0];
return driver->createImageFromData(irr::video::ECF_A8R8G8B8,
irr::core::dimension2du(size.Width, size.Height), data);
}
int main()
{
irr::IrrlichtDevice* const device = irr::createDevice(
irr::video::EDT_OPENGL, irr::core::dimension2du(800, 600));
irr::video::IVideoDriver* const driver = device->getVideoDriver();
irr::scene::ISceneManager* const smgr = device->getSceneManager();
irr::scene::ICameraSceneNode* const camera = smgr->addCameraSceneNode(0,
irr::core::vector3df(1.0f, 1.0, -3.5f));
camera->setTarget(irr::core::vector3df(1.0f, 0.5f, 0.5f));
//shader
irr::video::IGPUProgrammingServices* const gpu =
driver->getGPUProgrammingServices();
MyShaderCallBack* const mc = new MyShaderCallBack;
irr::s32 shaderMaterialType = gpu->addHighLevelShaderMaterial(
vertexShader.c_str(), "main", irr::video::EVST_VS_1_1,
fragmentShader.c_str(), "main", irr::video::EPST_PS_1_1, mc);
mc->drop();
//make texture out of an IImage
irr::video::IImage* image = createJapaneseFlagImage(driver);
irr::video::ITexture* texture = driver->addTexture("Another texture", image);
image->drop();
//shared material
irr::video::SMaterial material;
material.Lighting = false;
material.TextureLayer[0].Texture = texture;
material.TextureLayer[0].getTextureMatrix().setTextureScale(2, 2);
material.TextureLayer[0].getTextureMatrix().setTextureTranslate(0.5, 0);
//cube 1 with shader
{
irr::scene::IMeshSceneNode* node = smgr->addCubeSceneNode(1.0f);
node->getMaterial(0) = material;
node->setMaterialType((irr::video::E_MATERIAL_TYPE) shaderMaterialType);
}
//cube 2 without shader
{
irr::scene::IMeshSceneNode* node = smgr->addCubeSceneNode(1.0f, 0, -1,
irr::core::vector3df(1.5, 0, 0));
node->getMaterial(0) = material;
}
//cube 3 with vanilla texture
{
irr::scene::IMeshSceneNode* node = smgr->addCubeSceneNode(1.0f, 0, -1,
irr::core::vector3df(1.0, 1.5, 0.0));
node->setMaterialTexture(0, texture);
node->setMaterialFlag(irr::video::EMF_LIGHTING, false);
}
while (device->run())
{
driver->beginScene();
smgr->drawAll();
driver->endScene();
}
device->drop();
return 0;
}