UV precision & shading problem

Problems building or running the engine, queries about how to use features etc.
Post Reply
Peter.Lustig
Gnoblar
Posts: 6
Joined: Fri Aug 29, 2008 7:50 pm

UV precision & shading problem

Post by Peter.Lustig »

Hi Ogre community,

I have encountered a very strange shading issue and hope somebody has made similar experiences or knows what is going on.
I used the "Normal Mapping with Hardware Skinning and Specular" shader from the Ogre Wiki code snippets.
The geometry has about 13k vertices. What happens is that in areas where the UV coordinates are dense (close to each other but never overlapping) the polygons are rendered white. I figured that this is due to the specular component by leaving that out in the fragment shader. The diffuse component also appears wrong (only in those areas) but not as dramatic as the specular component.
Ok so my first thought was that there is something wrong with the model and how normals and tangents are arranged but those looks good to me. I was able to get rid of the unwanted shading artefacts by scaling the UV coordinated in that specific area by about 3 time its original size. Then my thinking was that it must be some precision problem but the UV coordinates Ogre writes out have 5 values after zero so that should be enough.
Now it gets really strange. I also wanted to make sure that this is not some sort of limitation problem I am facing so I took a simple cube and added some resolution to it, scaled the UVs of some arbitrary area to really tiny size (way smaller than the area I have problems with in my original geometry) - but guess what the problem does not occur. :shock:

Am I missing something or did anybody have experienced with similar problems?

Help greatly appreciated!
Peter.Lustig
Gnoblar
Posts: 6
Joined: Fri Aug 29, 2008 7:50 pm

Re: UV precision & shading problem

Post by Peter.Lustig »

Ahh well it turns out that the problem is due to zero tangent information being exported.
Why that is I don't know. It certainly must have something to do with the Maya exporter. As I mentioned the UV space is tight but not super tiny.

I am wondering if this has something to to with what is mentioned in the changelog of release 1.6.0:
now generates tangents based on a UV-area weighted, triangle angle weighted basis resulting in less biasing from small / thin triangles
Any hint greatly appreciated, I might find some time in the future to look into the Maya exporter.

Now here is what I did to make it work.

1. created two versions of the geometry, one with scaled UVs and one without
2. wrote a little python script that seeks for zero tangents in one file and replaces it with the correct one from the other (scaled version)

Here is the python script in case somebody runs into the same problems...

Code: Select all

# file with zero tangents
ZeroTagents = open("Old.xml", 'r')
zt_inputLines = ZeroTagents.readlines()
ZeroTagents.close()

# file with fixed tangents
GoodTagents = open("Tangents_OK.xml", 'r')
gt_inputLines = GoodTagents.readlines()
GoodTagents.close()

# see if file length is identical
if  len(zt_inputLines) !=  len(gt_inputLines):
    print ('files have different line size, contunie would create a huge mess so better abort!')     
    sys.exit()

# new file
fixedFile = open("Fixed_Tangents.xml", 'w')

# text to replace
stext = '<tangent x="0" y="0" z="0" />'

print len(zt_inputLines)

i = 0
for line in zt_inputLines:
	lineno = 0
  	lineno = string.find(line, stext)		
        if lineno >0:
		print "Found Tangent 0 0 0 at line "
		print i
		print "will replace it with"
		line = gt_inputLines[i]
		print line
        i = i+1;
	fixedFile.write(line)
fixedFile.close()	

print "Done Fixing Tangents"
Jusas
Halfling
Posts: 91
Joined: Mon May 14, 2007 9:14 am
x 8

Re: UV precision & shading problem

Post by Jusas »

Bumping this up since I just experienced the same problem (small UV coordinates) and solved it using an easier approach.

The idea is to temporarily multiply the coordinates enough to not generate a zero tangent before you calculate the tangent vectors and then restore the original UV coordinates. You could do this as a post-export phase to "fix" the tangents or alternatively when loading the model.

Sample code (multiplying UV coords by 100):

Code: Select all

                typedef std::vector< std::pair<float, float> > UV_PAIR;
                std::map<SubMesh*, UV_PAIR> uv_map;

                bool shared_save_handled = false;
                bool shared_restore_handled = false;

                Mesh::SubMeshIterator smIt = pEntity->getMesh()->getSubMeshIterator();
                while(smIt.hasMoreElements())
                {
                    SubMesh* submesh = smIt.getNext();

                    VertexData* vertex_data = submesh->useSharedVertices ? pEntity->getMesh()->sharedVertexData : submesh->vertexData;
                    if(submesh->useSharedVertices && shared_save_handled)
                        continue;
                    
                    const VertexElement* tc_elem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_TEXTURE_COORDINATES, 0);
                    Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(tc_elem->getSource());
                    unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
                    
                    float* pFloat;

                    for(size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
                    {
                        tc_elem->baseVertexPointerToElement(vertex, &pFloat);
                        std::pair<float, float> uvpair;
                        uvpair.first = (*pFloat);
                        *pFloat++ = (*pFloat) * 100.0f;
                        uvpair.second = (*pFloat);
                        *pFloat++ = (*pFloat) * 100.0f;
                        uv_map[submesh].push_back(uvpair);
                    }

                    vbuf->unlock();
                    
                    if(submesh->useSharedVertices)
                        shared_save_handled = true;

                }


                pEntity->getMesh()->buildTangentVectors(Ogre::VES_TANGENT);  // Recalculate the tangents


                smIt = pEntity->getMesh()->getSubMeshIterator();
                while(smIt.hasMoreElements())
                {
                    SubMesh* submesh = smIt.getNext();

                    VertexData* vertex_data = submesh->useSharedVertices ? pEntity->getMesh()->sharedVertexData : submesh->vertexData;
                    if(shared_restore_handled)
                        continue;

                    const VertexElement* tc_elem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_TEXTURE_COORDINATES, 0);
                    Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(tc_elem->getSource());
                    unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
                    
                    float* pFloat;

                    for(size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
                    {
                        std::pair<float, float> uvpair = uv_map[submesh].at(j);
                        tc_elem->baseVertexPointerToElement(vertex, &pFloat);
                        *pFloat++ = uvpair.first;
                        *pFloat++ = uvpair.second;
                    }

                    vbuf->unlock();

                    if(submesh->useSharedVertices)
                        shared_restore_handled = true;

                }

pEntity->_initialise(true); // Reinitialize the mesh
User avatar
GlowingPotato
Goblin
Posts: 211
Joined: Wed May 08, 2013 2:58 pm
x 10

Re: UV precision & shading problem

Post by GlowingPotato »

Just have this problem and the content of the old thread solved. Its 2016 lol
Post Reply