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?
-
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.pngvoid 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 }
-
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.
-
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