Shaders and Mipmapping

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
Post Reply
Klunk
Posts: 264
Joined: Mon Jan 10, 2011 5:21 pm

Shaders and Mipmapping

Post by Klunk »

when I, say, on terrain have a road texture (uvcoord1) blended to a terrain texture (uvcoord2) the mipmapping on the terrain texture seems to be controlled by the mipmapping on the road texture. So if the road texture is much smaller than the terrain texture, the terrain will be in the a much lower mip than adjacent non blended terrain. Obviously I can make all textures the same size so they all mip at the same rate but that makes getting a constant pixel density tricky. Is there any other way round this ? sorry this is in openGL btw.

Image
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Re: Shaders and Mipmapping

Post by REDDemon »

Interesting. try to enable anisotropic filtering only on the road texture and see if that still happens.
OpenGL says that every texture unit should behave according to glTexParameters. so it can be both a bug in mipmap settings of Irrlicht or a wrong implementation of GL of your video card. Have you tried on different PCs? You can still write a sader using a specific mipmap level but that is even trickier.
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: Shaders and Mipmapping

Post by hendu »

You can tell it to use a given mip level (texture2dLod), or add a bias.
Klunk
Posts: 264
Joined: Mon Jan 10, 2011 5:21 pm

Re: Shaders and Mipmapping

Post by Klunk »

it seems to be a bug either in my code or irrlicht, something to do with call driver->getTexture(filename) on a previously loaded texture leaves the previous texture with no mipmaps (hence the terrain in the image the terrain isn't mipping out but the new terrain in the blend is). It works ok if I duplicate the terrain texture and load the copy in the blend.
Klunk
Posts: 264
Joined: Mon Jan 10, 2011 5:21 pm

Re: Shaders and Mipmapping

Post by Klunk »

it seems to be an issue when the new terrain is set as a different texture index on the new material that is

if on the terrain material it would be

mat.setTexture(0,texture);

on the blending material the same texture is set as

mat.setTexture(1,texture);

this will cause loss of mipmaps on the original terrain material

if the terrain texture is set as

mat.setTexture(0,texture);

on the blend there's no loss of mipmaps :?

Image

the only difference between the two is the top right hand sphere has the displayed texture in the second texture slot. There is a very obvious and easy work around for me (i just need to swap two lines in the max shader, so the terrain texture is defined first). But this sort thing will bug me for ages :D
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: Shaders and Mipmapping

Post by hendu »

That does rather sound like an Irrlicht bug.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: Shaders and Mipmapping

Post by hybrid »

Could you please provide a test case which we can use to debug and fix this issue? So do you have a texture set in slot 0 as well? Because right now Irrlicht it might be required to use the texture slots consecutively. IIRC, we break at the first empty slot.
Klunk
Posts: 264
Joined: Mon Jan 10, 2011 5:21 pm

Re: Shaders and Mipmapping

Post by Klunk »

yes there is texture in slot 0 as well. the test case may be a quite a bit of work as It's all custom file format and non standard loader :oops:
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: Shaders and Mipmapping

Post by hybrid »

Uh, I thought you just created two spheres, a teexture and a plane, and just need to attack the shaders there... As we don't need the terrain obviously, and the spheres can be created with one Irrlicht call, without any loaders.
Klunk
Posts: 264
Joined: Mon Jan 10, 2011 5:21 pm

Re: Shaders and Mipmapping

Post by Klunk »

no the spheres were exported from max, the exporter exports Directx (.fx files) materials assigned to the spheres, along with all params. the loader then finds the appropriate glsl shader and reads out the params which are then passed to the correct extended shadercall back. works really well gives me a perfect wysiwyg between max and irrlicht unfortunately doesn't make for quick and easy test cases for you. I'll try and get round to creating a stand alone test case.
Klunk
Posts: 264
Joined: Mon Jan 10, 2011 5:21 pm

Re: Shaders and Mipmapping

Post by Klunk »

this will generate the same error, I copied straight over "HelloWorld" example with main.cpp and the 4 shaders go in the media folder.

main.cpp

Code: Select all

#include <irrlicht.h>
 
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
 
 
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
 
//***********************************************************************
 
class CCamSpaceLightAnim : public ISceneNodeAnimator
{
public:
 
        CCamSpaceLightAnim(ICameraSceneNode* cam, float offset, bool left) 
                : camera(cam), csoffset(0.5f * sin(PI/6.0f), 0.5f * cos(PI/6.0f),-cos(PI/6.0f)), doffset(offset)
        { 
                if(left)  
                        csoffset.X *= -1.0f;
        }
        virtual void animateNode(ISceneNode* node, u32 timeMs)
        {
                matrix4 camTM, lightTM;
                vector3df wsoffset;
                camera->getViewMatrix().getInverse(camTM);
                camTM.zeroTranslation();
                camTM.transformVect(wsoffset,csoffset);
                TransformFromDirVector(-wsoffset,  lightTM);
                node->setRotation(lightTM.getRotationDegrees());
                node->setPosition(wsoffset * doffset);
        }
        virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const {}
        virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) {}
        virtual ESCENE_NODE_ANIMATOR_TYPE getType() const { return ESNAT_UNKNOWN; }
        virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0) 
        { 
                return new CCamSpaceLightAnim(camera,doffset,false); 
        }
 
private:
 
        void TransformFromDirVector(const vector3df& dir, matrix4& mat)
        {
                vector3df up(0.0f,1.0f,0.0f), zaxis, xaxis, yaxis;
        zaxis = dir;
        zaxis.normalize();
        xaxis = up.crossProduct(zaxis);
        xaxis.normalize();
        yaxis = zaxis.crossProduct(xaxis);
        mat[0] = xaxis.X; mat[1] = xaxis.Y; mat[2] = xaxis.Z; mat[3] = 0;
        mat[4] = yaxis.X; mat[5] = yaxis.Y; mat[6] = yaxis.Z; mat[7] = 0;
        mat[8] = zaxis.X; mat[9] = zaxis.Y; mat[10] = zaxis.Z; mat[11] = 0;
        mat[12] = 0; mat[13] = 0; mat[14] = 0; mat[15] = 1;
        }
        vector3df                       csoffset;
        float                           doffset;
        ICameraSceneNode*       camera;
};
 
//***********************************************************************
 
#define LIGHT_INDEX             "glight"
#define AMBIENTCOLOUR   "gAmbient"
#define DIFFUSECOLOUR   "gDiffuse"
#define DIFFUSEMAP              "diffuseMapTexture"
#define BLENDTOMAP              "blendtoMapTexture"
 
class Terrain_Shader : public IShaderConstantSetCallBack
{
        u32                     light;
        SColorf         ambient;
        SColorf         diffuse;
        int                     diffuse_sampler;
 
public:
 
        Terrain_Shader() : light(0), ambient(0.0f,0.0f,0.0f), diffuse(1.0f,1.0f,1.0f), diffuse_sampler(0) {}
        virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData)
        {
                services->setVertexShaderConstant(LIGHT_INDEX, (float*)(&light), 1);
                services->setVertexShaderConstant(AMBIENTCOLOUR, (float*)(&ambient), 4);
                services->setVertexShaderConstant(DIFFUSECOLOUR, (float*)(&diffuse), 4);
                services->setPixelShaderConstant(DIFFUSEMAP,(float*)(&diffuse_sampler),1);
        }
};
 
//***********************************************************************
 
class BlendToTerrain_Shader : public IShaderConstantSetCallBack
{
        u32                     light;
        SColorf         ambient;
        SColorf         diffuse;
        int                     diffuse_sampler;
        int                     blend_sampler;
        
 
public:
 
        BlendToTerrain_Shader() : light(0), ambient(0.0f,0.0f,0.0f), 
                        diffuse(1.0f,1.0f,1.0f), diffuse_sampler(0) , blend_sampler(1) {}
 
        virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData)
        {
                services->setVertexShaderConstant(LIGHT_INDEX, (float*)(&light), 1);
                services->setVertexShaderConstant(AMBIENTCOLOUR, (float*)(&ambient), 4);
                services->setVertexShaderConstant(DIFFUSECOLOUR, (float*)(&diffuse), 4);
                services->setPixelShaderConstant(DIFFUSEMAP,(float*)(&diffuse_sampler),1);
                services->setPixelShaderConstant(BLENDTOMAP,(float*)(&blend_sampler),1);
        }
};
 
//***********************************************************************
 
int main()
{
        IrrlichtDevice *device = createDevice( video::EDT_OPENGL, dimension2d<u32>(640, 480), 16, false, false, false, 0);
 
        if (!device)
                return 1;
 
        device->setWindowCaption(L"Test mipmap");
 
        IVideoDriver* driver = device->getVideoDriver();
        ISceneManager* smgr = device->getSceneManager();
 
// add spheres
 
        IMeshSceneNode* sphereNode1 = smgr->addSphereSceneNode(50,16,smgr->getRootSceneNode(),999,vector3df(100.0f,0.0,0.0));
        IMeshSceneNode* sphereNode2 = smgr->addSphereSceneNode(50,16,smgr->getRootSceneNode(),1000,vector3df(-100.0f,0.0,0.0));
 
// add camera
 
        ICameraSceneNode* cameraNode = smgr->addCameraSceneNodeMaya();;
 
// add a light
 
        ILightSceneNode* lightNode = smgr->addLightSceneNode(smgr->getRootSceneNode(),vector3df(0,0,0));
        lightNode->setLightType(ELT_DIRECTIONAL);
 
// add camera space animator
 
        ISceneNodeAnimator* anim = new CCamSpaceLightAnim(cameraNode,100.0f,false);
        if(anim)
        {
                lightNode->addAnimator(anim);
                anim->drop();
        }
 
        path blendtoVSfname = "../../media/blend_to_terrain.vert";
        path blendtoPSfname = "../../media/blend_to_terrain.frag"; 
 
        path terrainVSfname = "../../media/terrain.vert";
        path terrainPSfname = "../../media/terrain.frag"; 
        
        if (!driver->queryFeature(EVDF_PIXEL_SHADER_1_1) && !driver->queryFeature(EVDF_ARB_FRAGMENT_PROGRAM_1))
        {
                device->getLogger()->log("WARNING: Pixel shaders disabled ");
                blendtoPSfname = "";
                terrainVSfname = "";
        }
        if (!driver->queryFeature(EVDF_VERTEX_SHADER_1_1) && !driver->queryFeature(EVDF_ARB_VERTEX_PROGRAM_1))
        {
                device->getLogger()->log("WARNING: Vertex shaders disabled ");
                blendtoVSfname = "";
                terrainPSfname = "";
        }
 
        IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();
        s32 terrainShaderMat = 0;
        s32 blendtoShaderMat = 0;
        if (gpu)
        {
                Terrain_Shader* ts = new Terrain_Shader();
                terrainShaderMat = gpu->addHighLevelShaderMaterialFromFiles( terrainVSfname, "main", 
                                                EVST_VS_1_1, terrainPSfname, "main", EPST_PS_1_1, ts, EMT_SOLID);
                ts->drop();
 
                BlendToTerrain_Shader* bts = new BlendToTerrain_Shader();
                blendtoShaderMat = gpu->addHighLevelShaderMaterialFromFiles( blendtoVSfname, "main", 
                                                EVST_VS_1_1, blendtoPSfname, "main", EPST_PS_1_1, bts, EMT_SOLID);
                bts->drop();
        }
 
        sphereNode1->setMaterialType((E_MATERIAL_TYPE)terrainShaderMat);
        sphereNode2->setMaterialType((E_MATERIAL_TYPE)blendtoShaderMat);
 
        ITexture* texture;
        driver->setTextureCreationFlag(ETCF_CREATE_MIP_MAPS,  true);
 
        texture = driver->getTexture("../../media/wall.jpg");
        sphereNode1->setMaterialTexture(0, texture);
 
        texture = driver->getTexture("../../media/wall.bmp");
        sphereNode2->setMaterialTexture(0, texture);
 
        texture = driver->getTexture("../../media/wall.jpg");
        sphereNode2->setMaterialTexture(1, texture);
 
// dooo it
 
        while(device->run())
        {
                driver->beginScene(true, true, SColor(255,127,127,140));
                smgr->drawAll();
                driver->endScene();
        }
 
        device->drop();
 
        return 0;
}
 
blend_to_terrain.vert

Code: Select all

uniform int      glight;        
uniform vec4 gAmbient;                  
uniform vec4 gDiffuse;                          
 
void main()
{
        gl_Position = ftransform();
        vec3 N = gl_NormalMatrix * gl_Normal;   
        vec3 L =  gl_LightSource[glight].position;
        float lambert = 0.5 * dot(N,L) + 0.5;
        gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;
        gl_TexCoord[0].zw = gl_MultiTexCoord1.xy;
        gl_FrontColor = gl_Color * gl_LightSource[glight].diffuse * gDiffuse * (gAmbient +  lambert * lambert);
}
blend_to_terrain.frag

Code: Select all

 
uniform sampler2D diffuseMapTexture;
uniform sampler2D blendtoMapTexture;
 
void main()
{
/*      normally this but needs second map channel to work
 
        vec4 col = texture2D(diffuseMapTexture, vec2(gl_TexCoord[0].xy));
        vec4 bld = texture2D(blendtoMapTexture, vec2(gl_TexCoord[0].zw));
    gl_FragColor = gl_Color * lerp(bld,col,gl_Color.a); */
   
// so we've replaced with this     
   
        vec4 bld = texture2D(blendtoMapTexture, vec2(gl_TexCoord[0].xy));
    gl_FragColor = gl_Color * bld;
    
}
terrain.vert

Code: Select all

uniform int      glight;        
uniform vec4 gAmbient;                  
uniform vec4 gDiffuse;                          
 
 
void main()
{
        gl_Position = ftransform();
        vec3 N = gl_NormalMatrix * gl_Normal;   
        vec3 L =  gl_LightSource[glight].position;
        float lambert = 0.5 * dot(N,L) + 0.5;
        gl_TexCoord[0] = gl_MultiTexCoord0;
        gl_FrontColor = gl_Color * gl_LightSource[glight].diffuse * gDiffuse * (gAmbient +  lambert * lambert);
}
terrain.frag

Code: Select all

uniform sampler2D diffuseMapTexture;
 
void main()
{
        vec4 col = texture2D(diffuseMapTexture, vec2(gl_TexCoord[0]));
    gl_FragColor = col * gl_Color;
}
Klunk
Posts: 264
Joined: Mon Jan 10, 2011 5:21 pm

Re: Shaders and Mipmapping

Post by Klunk »

btw you can correct the issue by changing

Code: Select all

        texture = driver->getTexture("../../media/wall.bmp");
        sphereNode2->setMaterialTexture(0, texture);
 
        texture = driver->getTexture("../../media/wall.jpg");
        sphereNode2->setMaterialTexture(1, texture);

Code: Select all

        texture = driver->getTexture("../../media/wall.bmp");
        sphereNode2->setMaterialTexture(1, texture);
 
        texture = driver->getTexture("../../media/wall.jpg");
        sphereNode2->setMaterialTexture(0, texture);
and

Code: Select all

BlendToTerrain_Shader() : light(0), ambient(0.0f,0.0f,0.0f), 
                        diffuse(1.0f,1.0f,1.0f), diffuse_sampler(0), blend_sampler(1) {}

Code: Select all

BlendToTerrain_Shader() : light(0), ambient(0.0f,0.0f,0.0f), 
                        diffuse(1.0f,1.0f,1.0f), diffuse_sampler(1), blend_sampler(0) {}
Klunk
Posts: 264
Joined: Mon Jan 10, 2011 5:21 pm

Re: Shaders and Mipmapping

Post by Klunk »

is there a fix for this yet ?
Post Reply