Fragment Shader
-
Hey,
Ich habe einen ziemlich simplen Fragment Shader, der mir meine ShadowMap darstellt:
uniform sampler2D ShadowMap; void main() { vec4 ShadowCoord = gl_TexCoord[0]; vec4 texel = texture2D(ShadowMap, ShadowCoord.st); texel.rgb *= 0.2; gl_FragColor = texel * gl_Color; }
Die Sache ist nun, dass ich einen harten Übergang habe und dies gerne mit PCF verbessern würde. Habe auch schon Tutorials im Internet gesehen aber zum einen verstehe ich garnicht so richtig wie das überhaupt funktioniert und laufen an sich tut es auch nicht.
Wäre nett wenn mir da jemand helfen könnte!MfG
-
Ich sehe da kein Shadow-Mapping bei dem was du machst.
Das könnte maximal noch Light-Mapping sein.
Bei Shadow-Mapping liest mal Z-Werte aus der Shadow-Map, transformiert die Fragment-Koordinaten in den Light-Space, und vergleich den so errechneten Z-Wert des Fragments mit dem aus der Shadow-Map.
Wenn der transformierte Z-Wert des Fragments grösser ist als der in der Shadow-Map, dann liegt das Fragment im Schatten.
Bei PCF holt man sich dann z.B. 4 benachbarte Z-Werte aus der Shadow-Map, macht mit jedem einzeln nen Vergleich, und interpoliert die so erhaltenen Werte (z.B. 1 für Licht, 0 für Schatten) dann anhand der exakten Lookup-Position in der Shadow-Map.
-
Ich führe die meisten Berechnungen in meiner Anwendung durch und dieser Shader stellt es lediglich da - dies mache ich eben vorallem weil ich noch PCF integrieren möchte.
Es handelt sich aber definitiv nicht um eine Light-Map!
Meine Frage ist jetzt eher: Wie hole ich mir den z.B. 4 benachbarte Z-Werte aus der ShadowMap?
-
FShader schrieb:
Ich führe die meisten Berechnungen in meiner Anwendung durch und dieser Shader stellt es lediglich da - dies mache ich eben vorallem weil ich noch PCF integrieren möchte.
Es handelt sich aber definitiv nicht um eine Light-Map!
Wo ist dann der Z-Vergleich in deinem Shader?
Meine Frage ist jetzt eher: Wie hole ich mir den z.B. 4 benachbarte Z-Werte aus der ShadowMap?
Na indem du 3 weitere texture2D() machst wo du nen Offset auf die Texturkoordinaten draufrechnest?
-
Wie gesagt, wird vieles in der Anwendung gemacht
Orientiert sich in vielen Dingen an dem Tutorial:
http://www.paulsprojects.net/tutorials/smt/smt.htmlArbeite halt bloß mit FBO's und habe halt geringe Teile vom Code geändert aber letztendlich ist es eben die Basis!
Könntest du mir denn bitte die paar Zeilen eben schreiben/zeigen?
-
Orientiert sich in vielen Dingen an dem Tutorial:
http://www.paulsprojects.net/tutorials/smt/smt.htmlAha.
D.h. du verwendest ARB_shadow.
Was soll dann die "ShadowMap" in deinem Shader darstellen? Die gleiche Map die du mit ARB_shadow verwendest nochmal? Macht das Sinn?FShader schrieb:
Wie gesagt, wird vieles in der Anwendung gemacht
Naja, in der Anwendung kannst du den Z-Vergleich nicht machen. Du kannst ARB_shadow verwenden, dann sorgt ARB_shadow dafür dass irgendwo ein Z-Vergleich gemacht wird. Ob bzw. wie das dann mit Shadern zusammenspielt weiss ich nicht, die Extension scheint aus der Pre-Shader Ära zu kommen.
Ich hab' keine Erfahrung mit OpenGL, und erst recht keine mit ARB_shadow, aber auf den ersten Blick sieht mir das nicht so aus, als könnte man damit PCF machen - es sei denn der Treiber deiner Grafikkarte macht es netterweise selbst (und/oder es lässt sich über weitere Extensions "aktivieren").
Wenn *du* PCF *selbst* implementieren willst, dann wirst du *vermutlich* GL_ARB_shadow aufgeben müssen, und das Shadow-Mapping direkt im Shader-Code machen.
Könntest du mir denn bitte die paar Zeilen eben schreiben/zeigen?
Nö
BTW: Zeit mal ein Bild her von dem was dein Programm ausspuckt. Vielleicht macht dein Treiber sowieso schon PCF, und du erwartest dir einfach nur zuviel...
-
Also der Treiber macht definitiv kein PCF, 100%ig.
Ich wollte mich nun erstmal an einem neuen Tutorial orietieren, da vorallem dort PCF gezeigt wird!http://fabiensanglard.net/shadowmappingPCF/index.php
Die Sache ist, wenn ich mir die fertige exe downloade und ausführe, dann werden zwar die Objekte gerendert aber ein Schatten wird nicht angezeigt (zumindest alles andere als richtig). Habe daher das Projekt mal selber compiled mit dem selben Ergebnis! Hab schon das FBO gegen meins ausgetauscht und einiges mehr aber es will nicht funktionieren! Ich packe daher einfach mal den Code hier rein - vllt. fällt ja jemanden etwas auf! Code an sich sollte übersichtlich sein.
#include <iostream> #include <cmath> #include <cstdio> #include "gl/glew.h" #include "gl/freeglut.h" using namespace std; const int RENDER_WIDTH = 1024; const int RENDER_HEIGHT = 768; const int ShadowMapSize = 512; float p_camera[3] = {35,25,5}; float l_camera[3] = {0,-7,-25}; float p_light[3] = {3,16,0}; float l_light[3] = {0,0,-5}; float light_mvnt = 30.0f; GLuint fboId; GLuint depthTextureId; GLuint shadowShaderId; GLuint shadowMapUniform; GLuint shadowMapStepXUniform; GLuint shadowMapStepYUniform; char *textFileRead(char *fn) { FILE *fp; char *content = NULL; size_t count=0; if (fn != NULL) { fopen_s(&fp, fn,"rt"); if (fp != NULL) { fseek(fp, 0, SEEK_END); count = ftell(fp); rewind(fp); if (count > 0) { content = (char *)malloc(sizeof(char) * (count+1)); count = fread(content,sizeof(char),count,fp); content[count] = '\0'; } fclose(fp); } } return content; } void loadShadowShader() { GLuint v, f; char *vs = NULL, *fs = NULL; v = glCreateShader(GL_VERTEX_SHADER); f = glCreateShader(GL_FRAGMENT_SHADER); vs = textFileRead("VertexShader.c"); fs = textFileRead("FragmentShader.c"); const char * vv = vs; const char * ff = fs; glShaderSource(v, 1, &vv,NULL); glShaderSource(f, 1, &ff,NULL); delete vs; delete fs; glCompileShader(v); glCompileShader(f); shadowShaderId = glCreateProgram(); glAttachShader(shadowShaderId, v); glAttachShader(shadowShaderId, f); glLinkProgram(shadowShaderId); glUseProgram(shadowShaderId); shadowMapUniform = glGetUniformLocation(shadowShaderId, "ShadowMap"); shadowMapStepXUniform = glGetUniformLocation(shadowShaderId, "xPixelOffset"); shadowMapStepYUniform = glGetUniformLocation(shadowShaderId, "yPixelOffset"); } void generateShadowFBO() { glGenTextures(1, &depthTextureId); glBindTexture(GL_TEXTURE_2D, depthTextureId); glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, ShadowMapSize, ShadowMapSize, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); float cp[] = {1,1,1,1}; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, cp); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); glBindTexture(GL_TEXTURE_2D, 0); glGenFramebuffers(1, &fboId); glBindFramebuffer(GL_FRAMEBUFFER, fboId); glDrawBuffer(GL_NONE); glReadBuffer(GL_NONE); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTextureId, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); } void setupMatrices(float position_x,float position_y,float position_z,float lookAt_x,float lookAt_y,float lookAt_z, bool mode) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (mode) gluPerspective(45, 1.0, 1.0, 1000.0); else gluPerspective(45, (double)RENDER_WIDTH/RENDER_HEIGHT, 1.0, 1000.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(position_x,position_y,position_z,lookAt_x,lookAt_y,lookAt_z,0,1,0); } void update(void) { p_light[0] = light_mvnt * cos(glutGet(GLUT_ELAPSED_TIME)/1000.0f); p_light[2] = light_mvnt * sin(glutGet(GLUT_ELAPSED_TIME)/1000.0f); } void setTextureMatrix(void) { static double modelView[16]; static double projection[16]; const GLdouble bias[16] = { 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.5, 0.5, 1.0}; // Grab modelview and transformation matrices glGetDoublev(GL_MODELVIEW_MATRIX, modelView); glGetDoublev(GL_PROJECTION_MATRIX, projection); glMatrixMode(GL_TEXTURE); glActiveTexture(GL_TEXTURE7); glLoadIdentity(); glLoadMatrixd(bias); // concatating all matrice into one. glMultMatrixd (projection); glMultMatrixd (modelView); // Go back to normal matrix mode glMatrixMode(GL_MODELVIEW); } void startTranslate(float x,float y,float z) { glPushMatrix(); glTranslatef(x,y,z); glMatrixMode(GL_TEXTURE); glActiveTexture(GL_TEXTURE7); glPushMatrix(); glTranslatef(x,y,z); } void endTranslate() { glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } void drawObjects(void) { // Ground glColor4f(0.3f,0.3f,0.3f,1); glBegin(GL_QUADS); glVertex3f(-45,2,-45); glVertex3f(-45,2, 55); glVertex3f( 55,2, 55); glVertex3f( 55,2,-45); glEnd(); glColor4f(0.9f,0.9f,0.9f,1); // Instead of calling glTranslatef, we need a custom function that also maintain the light matrix startTranslate(0,4,-16); glutSolidCube(4); endTranslate(); startTranslate(0,4,-5); glutSolidSphere(4,40,40); endTranslate(); } void renderScene(void) { update(); glUseProgram(0); //Render Scene => FBO glBindFramebuffer(GL_FRAMEBUFFER, fboId); glClear( GL_DEPTH_BUFFER_BIT); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glViewport(0, 0, ShadowMapSize, ShadowMapSize); setupMatrices(p_light[0],p_light[1],p_light[2],l_light[0],l_light[1],l_light[2], true); glCullFace(GL_FRONT); drawObjects(); setTextureMatrix(); glBindFramebuffer(GL_FRAMEBUFFER,0); glViewport(0,0, (int)RENDER_WIDTH, (int)RENDER_HEIGHT); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Using the shadow shader glUseProgram(shadowShaderId); glActiveTexture(GL_TEXTURE7); glUniform1i(shadowMapUniform, 7); glBindTexture(GL_TEXTURE_2D,depthTextureId); glUniform1f(shadowMapStepXUniform, 1.0/ ShadowMapSize); glUniform1f(shadowMapStepYUniform, 1.0/ ShadowMapSize); setupMatrices(p_camera[0],p_camera[1],p_camera[2],l_camera[0],l_camera[1],l_camera[2], false); glCullFace(GL_BACK); drawObjects(); // DEBUG only. this piece of code draw the depth buffer onscreen glUseProgram(0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-RENDER_WIDTH/2,RENDER_WIDTH/2,-RENDER_HEIGHT/2,RENDER_HEIGHT/2,1,20); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glColor4f(1,1,1,1); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,depthTextureId); glEnable(GL_TEXTURE_2D); glTranslated(0,0,-1); glBegin(GL_QUADS); glTexCoord2d(0,0);glVertex3f(0,0,0); glTexCoord2d(1,0);glVertex3f(RENDER_WIDTH/2,0,0); glTexCoord2d(1,1);glVertex3f(RENDER_WIDTH/2,RENDER_HEIGHT/2,0); glTexCoord2d(0,1);glVertex3f(0,RENDER_HEIGHT/2,0); glEnd(); glDisable(GL_TEXTURE_2D); glUseProgram(shadowShaderId); glutSwapBuffers(); glutPostRedisplay(); } void processNormalKeys(unsigned char key, int x, int y) { if (key == 27) exit(0); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH); glutInitWindowPosition(100,100); glutInitWindowSize((int)RENDER_WIDTH, (int)RENDER_HEIGHT); glutCreateWindow("GLSL Shadow mapping"); glewInit(); generateShadowFBO(); loadShadowShader(); // This is important, if not here, FBO's depthbuffer won't be populated. glEnable(GL_DEPTH_TEST); glClearDepth(1.0); glDepthFunc(GL_LEQUAL); glClearColor(0,0,0,1.0f); glEnable(GL_CULL_FACE); glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); glutDisplayFunc(renderScene); glutKeyboardFunc(processNormalKeys); glutMainLoop(); return 0; }
VertexShader:
varying vec4 ShadowCoord; void main() { ShadowCoord= gl_TextureMatrix[7] * gl_Vertex; gl_Position = ftransform(); gl_FrontColor = gl_Color; }
FragmentShader:
uniform sampler2DShadow ShadowMap; varying vec4 ShadowCoord; uniform float xPixelOffset ; uniform float yPixelOffset ; float lookup( vec2 offSet) { return shadow2DProj(ShadowMap, ShadowCoord + vec4(offSet.x * xPixelOffset * ShadowCoord.w, offSet.y * yPixelOffset * ShadowCoord.w, 0.05, 0.0) ).w; } void main() { float shadow ; if (ShadowCoord.w > 1.0) { float x,y; for (y = -3.5 ; y <=3.5 ; y+=1.0) for (x = -3.5 ; x <=3.5 ; x+=1.0) shadow += lookup(vec2(x,y)); shadow /= 64.0 ; } gl_FragColor = (shadow+0.2) * gl_Color; }
Für mich sieht es so aus, als ob garkeine depth-texture ins FBO kommt, was mich aber wundert, da ich eben auch ein FBO von mir genommen habe was definitiv funktioniert - der Fehler muss also noch woanders liegen.
Ps. Ich hatte mir auch mal sein normales ShadowMapping angeschaut und muss sagen, dass es auch dort ein Fehler gibt.
Im Fragment Shader will er z.B. eine vec4 Variable an texture2D übergeben - läuft natürlich nicht. Als vec2 mit .st oder texture2DProj und dann vec4 läuft. Fehler sind wohl keine Seltenheit.