heightmap via normals beleuchten:



  • Ich wollte meine Heightmap so beleuchten, dass die Kanten nicht so enorm unterschiedlich beleuchtet werden.
    Dazu habe ich was zum Berechnen der Normalvektoren vorbereitet:

    inline st3KOVec CalcNormal(st3KOVec v1, st3KOVec v2, st3KOVec v3)
    {
       double v1x,v1y,v1z,v2x,v2y,v2z;
       double nx,ny,nz;
       double vLen;
    
       st3KOVec Result;
    
       // Calculate vectors
       v1x = v1.x - v2.x;
       v1y = v1.y - v2.y;
       v1z = v1.z - v2.z;
    
       v2x = v2.x - v3.x;
       v2y = v2.y - v3.y;
       v2z = v2.z - v3.z;
    
       // Get cross product of vectors
       nx = (v1y * v2z) - (v1z * v2y);
       ny = (v1z * v2x) - (v1x * v2z);
       nz = (v1x * v2y) - (v1y * v2x);
    
       // Normalise final vector
       vLen = sqrt( (nx * nx) + (ny * ny) + (nz * nz) );
    
       Result.x = (float)(nx / vLen);
       Result.y = (float)(ny / vLen);
       Result.z = (float)(nz / vLen);
    
       return Result;
    }
    
    inline st3KOVec addVec(st3KOVec v1, st3KOVec v2)
    {
       st3KOVec Result;
    
       Result.x = v1.x + v2.x;
       Result.y = v1.y + v2.y;
       Result.z = v1.z + v2.z;
    
       return Result;
    }
    

    Schließlich setze ich dann die Punkte und berechne die Normals, aber leider ist das Ergebnis noch nicht besonders gut. Zur Lichtquelle positionierte Flächen werden halt sehr stark beleuchtet und andere Sachen kaum. Das macht die Heightmap halt auch nicht schöner.

    for ( int Y = 0; Y < (iLengthMap-iStepSize); Y += iStepSize ) {
    		for ( int X = 0; X < (iWidthMap-iStepSize); X += iStepSize )
    		{
    // ...
                            // Punkte der Fläche berechnen:
                            // Get The (X, Y, Z) Value For The Bottom Left Vertex
                            svP1.x = X; svP1.y = fHeightMap[Y][X]; svP1.z = -Y;
                            // Get The (X, Y, Z) Value For The Top Left Vertex
                            svP2.x = X; svP2.y = fHeightMap[Y+iStepSize][X]; svP2.z = -Y - iStepSize; 
                            // Get The (X, Y, Z) Value For The Top Right Vertex
                            svP3.x = X + iStepSize; svP3.y = fHeightMap[Y+iStepSize][X+iStepSize]; svP3.z = -Y - iStepSize; 
                            // Get The (X, Y, Z) Value For The Bottom Right Vertex
                            svP4.x = X + iStepSize; svP4.y = fHeightMap[Y][X+iStepSize]; svP4.z = -Y;
    
                            // Normals berechnen und festsetzen
                            svNorm = CalcNormal(svP1, svP2, svP3);
                            svNorm = addVec(CalcNormal(svP1, svP3, svP4), svNorm);
                            svNorm = addVec(CalcNormal(svP2, svP3, svP4), svNorm);
                            svNorm = addVec(CalcNormal(svP1, svP2, svP4), svNorm);
                            glNormal3f(svNorm.x, svNorm.y, svNorm.z);
    

    Weis jemand wie ich die Berechnung verbessern kann?


  • Mod

    das problem ist wohl dass du viele vektoren aufeinander addierst, das ist nicht mehr normalisiert.

    statt also jede normale einzeln zu normalisieren, normalisiere nur das aufsummierte resultat. das koennte bessere ergebnisse liefern 😉



  • ich bin mir nicht sicher was du meinst.



  • du addierst 4 vektoren der laenge 1. wie lang ist das ergebnis?



  • inline st3KOVec calcVec(st3KOVec v1, st3KOVec v2, st3KOVec v3)
    {
       double v1x,v1y,v1z,v2x,v2y,v2z;
       double nx,ny,nz;
       double vLen;
    
       st3KOVec Result;
    
       // Calculate vectors
       v1x = v1.x - v2.x;
       v1y = v1.y - v2.y;
       v1z = v1.z - v2.z;
    
       v2x = v2.x - v3.x;
       v2y = v2.y - v3.y;
       v2z = v2.z - v3.z;
    
       // Get cross product of vectors
       nx = (v1y * v2z) - (v1z * v2y);
       ny = (v1z * v2x) - (v1x * v2z);
       nz = (v1x * v2y) - (v1y * v2x);
    
       Result.x = (float)(nx);
       Result.y = (float)(ny);
       Result.z = (float)(nz);
    
       return Result;
    }
    
    inline st3KOVec CalcNormalInQuad(st3KOVec v1, st3KOVec v2, st3KOVec v3, st3KOVec v4)
    {
       double vLen;
    
       st3KOVec pResult[4];
       st3KOVec Result;
       Result.x = 0; Result.y = 0; Result.z = 0;
    
       pResult[0] = calcVec(v1, v2, v3);
       pResult[1] = calcVec(v1, v3, v4);
       pResult[2] = calcVec(v2, v3, v4);
       pResult[3] = calcVec(v1, v2, v4);
    
       for(int i = 0; i < 4; i++) {
          Result.x += pResult[i].x;
          Result.y += pResult[i].y;
          Result.z += pResult[i].z;
       }
    
       vLen = sqrt( (Result.x * Result.x) + (Result.y * Result.y) + (Result.z * Result.z) );
    
       Result.x = (float)(Result.x / vLen);
       Result.y = (float)(Result.y / vLen);
       Result.z = (float)(Result.z / vLen);
    
       return Result;
    }
    

    irgendwie ist dises ergebnis auch nicht so gut



  • Am besten Du machst mal 'nen Screenshot...



  • ich weis nicht ob das so sein muss oder nicht, aber es muss doch ne möglichkeit geben, weichere übergänge zu schaffen: das ist der code bei stepsize = 2; es sieht nicht groß anders aus, als wenn ich mit der geposteten funktion von oben die normals pro quad mit lediglich 3 punkten berechne.

    http://img76.imageshack.us/img76/5161/bildschirmphoto9xt2.th.png
    http://img399.imageshack.us/img399/6480/bildschirmphoto10tg5.th.png

    void Map::drawMap(int iStepSize, bool bRenderQuads)
    {
    	if(!bHMapLoaded)
    		return;
    
    	// Lichter setzen
    	if(bStaticLightsLoaded) {
    		glLightfv(GL_LIGHT1, GL_AMBIENT, fLightAmbient);
    		glLightfv(GL_LIGHT1, GL_DIFFUSE, fLightDiffuse);
    		glLightfv(GL_LIGHT1, GL_POSITION,fLightPosition);
    		glEnable(GL_LIGHT1);
    	}
    
    	float x, y, z;
    	GLint w, h;
    
            st3KOVec svP1, svP2, svP3, svP4;
            st3KOVec svNorm;
    // 	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    	for ( int Y = 0; Y < (iLengthMap-iStepSize); Y += iStepSize ) {
    		for ( int X = 0; X < (iWidthMap-iStepSize); X += iStepSize )
    		{
    			// wenn Textur initialisiert wurde ^_^ sonst würdes abstürzen
    			if(gHMapTextures[Y][X] > 0) {
    				glBindTexture(GL_TEXTURE_2D, gHMapTextures[Y][X]);
    // 				glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
    // 				glGetTexLevelParameteriv (GL_TEXTURE_2D, 0,GL_TEXTURE_HEIGHT, &h);
    			}
    
                            // Punkte der Fläche berechnen:
                            // Get The (X, Y, Z) Value For The Bottom Left Vertex
                            svP1.x = X; svP1.y = fHeightMap[Y][X]; svP1.z = -Y;
                            // Get The (X, Y, Z) Value For The Top Left Vertex
                            svP2.x = X; svP2.y = fHeightMap[Y+iStepSize][X]; svP2.z = -Y - iStepSize; 
                            // Get The (X, Y, Z) Value For The Top Right Vertex
                            svP3.x = X + iStepSize; svP3.y = fHeightMap[Y+iStepSize][X+iStepSize]; svP3.z = -Y - iStepSize; 
                            // Get The (X, Y, Z) Value For The Bottom Right Vertex
                            svP4.x = X + iStepSize; svP4.y = fHeightMap[Y][X+iStepSize]; svP4.z = -Y;
    
                            // Normals berechnen und festsetzen
                            svNorm = CalcNormalInQuad(svP1, svP2, svP3, svP4);
    //                         svNorm = CalcNormal(svP1, svP2, svP3);
                            glNormal3f(svNorm.x, svNorm.y, svNorm.z);
    
                            if(bRenderQuads)               // What We Want To Render
                                     glBegin( GL_QUADS );  // Render Polygons
                            else 
                                     glBegin( GL_LINE_LOOP );  // Render Lines Instead
    			// Get The (X, Y, Z) Value For The Bottom Left Vertex
    			if(gHMapTextures[Y][X] > 0) glTexCoord2f(0.0f, 1.0f); glVertex3i(svP1.x, svP1.y, svP1.z);// Send This Vertex To OpenGL To Be Rendered
    			// Get The (X, Y, Z) Value For The Top Left Vertex
    			if(gHMapTextures[Y][X] > 0) glTexCoord2f(0.0f, 0.0f); glVertex3i(svP2.x, svP2.y, svP2.z);// Send This Vertex To OpenGL To Be Rendered
    			// Get The (X, Y, Z) Value For The Top Right Vertex
    			if(gHMapTextures[Y][X] > 0) glTexCoord2f(1.0f, 0.0f); glVertex3i(svP3.x, svP3.y, svP3.z);// Send This Vertex To OpenGL To Be Rendered
    			// Get The (X, Y, Z) Value For The Bottom Right Vertex
    			if(gHMapTextures[Y][X] > 0) glTexCoord2f(1.0f, 1.0f); glVertex3i(svP4.x, svP4.y, svP4.z);// Send This Vertex To OpenGL To Be Rendered
    
    	                glEnd();
    		}
    	}
    
    	// Zeichne nun die Modelle
    	for(int i = 0; i < vStaticModels.size(); i++)
    		vStaticModels.at(i)->draw();
    
    	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);// reset the color to white
    }
    

  • Mod

    eventuell

    glShadeModel
    mit
    gl_smooth
    😉



  • int display::initGL()
    {
    	glViewport(0, 0, screenWidth, screenHeight);
    	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);		// This Will Clear The Background Color To Black
    	glClearDepth(1.0);				// Enables Clearing Of The Depth Buffer
    	glDepthFunc(GL_LESS);				// The Type Of Depth Test To Do
    
    	glShadeModel(GL_SMOOTH);			// Enables Smooth Color Shading
    
    	glMatrixMode(GL_PROJECTION);
    	glLoadIdentity();				// Reset The Projection Matrix
    
    	gluPerspective(45.0f,(GLfloat)screenWidth/(GLfloat)screenHeight,0.1f,5000.0f);	// Calculate The Aspect Ratio Of The Window
    
    	glMatrixMode(GL_MODELVIEW);
    
    	glEnable(GL_VERTEX_ARRAY);
    	glEnable(GL_DEPTH_TEST);			// Enables Depth Testing
    	glEnable(GL_TEXTURE_2D);			// Enable Texture Mapping
    	glEnable(GL_TEXTURE_COORD_ARRAY);
    	glEnable(GL_LIGHTING);
    
    	return 1;
    }
    


  • Du musst jedem Eckpunkt eine eigene Normale mitgeben anstatt eine einzige pro Polygon zu setzen.


  • Mod

    du nimmst die 4punkte die ein quad aufziehen und berechnest fuer sie eine normale. entsprechend hast du pro face eine normale.
    alternative waere die 4 nachbarpunkte von einem vertex zu nehmen und daraus die normale zu mitteln.

    also statt

    +-+
    | |
    +-+
    

    eher

    +
      |
    +-+-+
      |
      +
    


  • Das was auf den Bildern zu sehen ist, sieht aus wie flat Schading 😉
    Ich habe jetzt nicht die andere Antworten gelsesen und es kann sein , das dies schon gesagt wurde. Es ist wichtig, das du für jeden Vertex eine Normale berechnest(und mit angibst), diese wiederum möglichst als Mittelwert von den benachbarten Normalen.



  • also, ich habe jetzt eine funktion gemacht die nun die normalen berechnet, ich hoffe das die nun richtig ist:

    (die inline funktionen habe ich auch angepasst)
    die normals in ein array zu packen hat auch den vorteil, dass es schneller ist, weil die nicht jedesmal neu berechnet werden müssen, wenn was gemalt werden soll. ist viel schneller als vorher!!!

    void Map::calcNormals(int iStepSize) {
       st3KOVec svPup, svPdown, svPleft, svPright, svPcenter;
       st3KOVec result;
       for ( int Y = iStepSize; Y < (iLengthMap-iStepSize); Y += iStepSize ) {
          for ( int X = iStepSize; X < (iWidthMap-iStepSize); X += iStepSize )
          {
             // Punkte der Fläche berechnen:
             svPcenter.x = X; svPcenter.y = fHeightMap[Y][X]; svPcenter.z = -Y;
             svPup.x = X; svPup.y = fHeightMap[Y+iStepSize][X]; svPup.z = -Y - iStepSize; 
             svPdown.x = X; svPdown.y = fHeightMap[Y-iStepSize][X]; svPdown.z = -Y + iStepSize; 
             svPleft.x = X - iStepSize; svPleft.y = fHeightMap[Y][X-iStepSize]; svPleft.z = -Y;
             svPright.x = X + iStepSize; svPright.y = fHeightMap[Y][X+iStepSize]; svPright.z = -Y;
    
             result = CalcNormalInQuad(svPright, svPleft, svPup, svPdown, svPcenter);
             vNormals[Y][X] = result;
          }
       }
    }
    

    aber die beleuchtung scheint realistischer zu sein!!! aber leider kriege ich kein smooth shading hin, kurios.



  • Tust Du so?

    glBegin(GL_QUADS);
    
                glTexCoord2f(0.0f, 1.0f);
                glNormal3f( ... );
                glVertex3i(svP1.x, svP1.y, svP1.z);
    
                glTexCoord2f(0.0f, 0.0f);
                glNormal3f( ... );
                glVertex3i(svP2.x, svP2.y, svP2.z);
    
                glTexCoord2f(1.0f, 0.0f);
                glNormal3f( ... );
                glVertex3i(svP3.x, svP3.y, svP3.z);
    
                glTexCoord2f(1.0f, 1.0f); 
                glNormal3f( ... );
                glVertex3i(svP4.x, svP4.y, svP4.z);
    
                glEnd();
    


  • hast recht, habs endlich geschafft


Log in to reply