sources gl_lighting gl_ambient example color c++ graphics opengl glsl glm-math lighting

c++ - gl_ambient - opengl gl_lighting



El mapeo normal saliĆ³ terriblemente mal (2)

Traté de implementar el mapeo normal en mi aplicación opengl pero no puedo hacer que funcione.

This es el mapa difuso (al que agrego un color marrón) y this es el mapa normal.

Para obtener los vectores tangente y bitangente (en otros lugares llamados binormales?), Ejecuto esta función para cada triángulo en mi malla:

void getTangent(const glm::vec3 &v0, const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec2 &uv0, const glm::vec2 &uv1, const glm::vec2 &uv2, std::vector<glm::vec3> &vTangents, std::vector<glm::vec3> &vBiangents) { // Edges of the triangle : postion delta glm::vec3 deltaPos1 = v1-v0; glm::vec3 deltaPos2 = v2-v0; // UV delta glm::vec2 deltaUV1 = uv1-uv0; glm::vec2 deltaUV2 = uv2-uv0; float r = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x); glm::vec3 tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y)*r; glm::vec3 bitangent = (deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x)*r; for(int i = 0; i < 3; i++) { vTangents.push_back(tangent); vBiangents.push_back(bitangent); } }

Después de eso, llamo a glBufferData para cargar los vértices, normales, uvs, tangentes y bitangentes a la GPU. El sombreador de vértices:

#version 430 uniform mat4 ProjectionMatrix; uniform mat4 CameraMatrix; uniform mat4 ModelMatrix; in vec3 vertex; in vec3 normal; in vec2 uv; in vec3 tangent; in vec3 bitangent; out vec2 fsCoords; out vec3 fsVertex; out mat3 TBNMatrix; void main() { gl_Position = ProjectionMatrix * CameraMatrix * ModelMatrix * vec4(vertex, 1.0); fsCoords = uv; fsVertex = vertex; TBNMatrix = mat3(tangent, bitangent, normal); }

Sombreador de fragmentos:

#version 430 uniform sampler2D diffuseMap; uniform sampler2D normalMap; uniform mat4 ModelMatrix; uniform vec3 CameraPosition; uniform struct Light { float ambient; vec3 position; } light; uniform float shininess; in vec2 fsCoords; in vec3 fsVertex; in mat3 TBNMatrix; out vec4 color; void main() { //base color const vec3 brownColor = vec3(153.0 / 255.0, 102.0 / 255.0, 51.0 / 255.0); color = vec4(brownColor * (texture(diffuseMap, fsCoords).rgb + 0.25), 1.0);//add a fixed base color (0.25), because its dark as hell //general vars vec3 normal = texture(normalMap, fsCoords).rgb * 2.0 - 1.0; vec3 surfacePos = vec3(ModelMatrix * vec4(fsVertex, 1.0)); vec3 surfaceToLight = normalize(TBNMatrix * (light.position - surfacePos)); //unit vector vec3 eyePos = TBNMatrix * CameraPosition; //diffuse float diffuse = max(0.0, dot(normal, surfaceToLight)); //specular float specular; vec3 incidentVector = -surfaceToLight; //unit vec3 reflectionVector = reflect(incidentVector, normal); //unit vector vec3 surfaceToCamera = normalize(eyePos - surfacePos); //unit vector float cosAngle = max(0.0, dot(surfaceToCamera, reflectionVector)); if(diffuse > 0.0) specular = pow(cosAngle, shininess); //add lighting to the fragment color (no attenuation for now) color.rgb *= light.ambient; color.rgb += diffuse + specular; }

La imagen que obtengo es completamente incorrecta. (luz colocada en la cámara)

¿Qué estoy haciendo mal aquí?


Intentaré hacer que tu código funcione. ¿Lo has probado con cámara en movimiento?

No puedo ver en ninguna parte que haya transformado la TBNMatrix con las matrices de transformación, vista y modelo. ¿ vec3 normal = TBNMatrix[2]; con el vec3 normal = TBNMatrix[2]; normales originales? (Fragmento sombreador)

Lo siguiente podría ayudar. En el sombreador Vertex tienes:

uniform mat4 ProjectionMatrix; uniform mat4 CameraMatrix; uniform mat4 ModelMatrix;

Sin embargo, aquí solo se deben usar estas 3 matrices:

uniform mat4 PCM; uniform mat4 MIT; //could be mat3 uniform mat4 ModelMatrix; //could be mat3

Es más eficiente calcular el producto de esas matrices en la CPU (y produce el mismo porque la multiplicación de matrices es asociativa). Entonces este producto, el PCM se puede usar para calcular la nueva posición con una multiplicación por vértice:

gl_Position = PCM * vec4(vertex, 1.0);

El MIT es la transposición inversa de ModelMatrix , debe calcularlo en la CPU. Esto se puede usar para transformar las normales:

vec4 tang = ModelMatrix*vec4(tangent,0); vec4 bita= ModelMatrix*vec4(bitangent,0); vec4 norm= PCMIT*vec4(tangent,0); TBNMatrix = mat3(normalize(tang.xyz), normalize(bita.xyz), normalize(normal.xyz));

No estoy seguro de qué sucede con la tangente y la bitangente, pero de esta manera lo normal se mantendrá perpendicular a ellas. Es fácil de probar. Aquí uso a ° b como el producto skalar de los vectores ayb. Entonces, n sea algo normal, y a es un vector en la superficie (por ejemplo, {bi} tangente, borde de un triángulo), y sea A cualquier transformación. Entonces:

0 = an = A ^ (- 1) A a ° n = A a ° A ^ (- T) n = 0

Donde utilicé la igualdad A x ° y = x ° A ^ T y. Por lo tanto, si a es perpendicular a n, entonces A a es perpendicular a A ^ (- T) n, por lo que tenemos que transformarlo con la transposición inversa de la matriz. Sin embargo, lo normal debe tener una longitud de 1, por lo que después de las transformaciones, debe normalizarse.

También puede obtener una normalidad perpendicular haciendo esto:

vec3 normal = normalize(cross(tangent, bitangent));

Donde cross (a, b) es la función que calcula el producto cruzado de a y b, la bruja siempre es perpendicular a a y b.

Lo siento por mi ingles :)


Mi apuesta es la configuración de color / mezcla en fragment shader ...

  1. está configurando el color de salida más de una vez

    Si recuerdo correctamente en algunos controladores gfx que hacen un gran problema, por ejemplo, todo después de la línea

    color = vec4(brownColor * (texture(diffuseMap, fsCoords).rgb + 0.25), 1.0);//add a fixed base color (0.25), because its dark as hell

    podría ser eliminado por el conductor ...

  2. agrega color e intensities lugar de color*intensity

    pero podría pasar por alto algo.

  3. prueba solo el sombreado normal / irregular al principio

    Ignora el ambiente, el reflejo, el especular ... y luego, si funciona, agrega el resto uno por uno. Compruebe siempre los registros de compilación del sombreador

Demasiado perezoso para analizar aún más su código, así que así es como lo hago:

El tamaño de la izquierda es el objeto de la nave espacial (similar al Viper de ZXS Elite) renderizado con una función fija. Lado derecho igual (una rotación de objeto un poco diferente) con el sombreador GLSL en su lugar y este mapa normal / de relieve

[Vértice]

//------------------------------------------------------------------ #version 420 core //------------------------------------------------------------------ // texture units: // 0 - texture0 map 2D rgba // 1 - texture1 map 2D rgba // 2 - normal map 2D xyz // 3 - specular map 2D i // 4 - light map 2D rgb rgb // 5 - enviroment/skybox cube map 3D rgb uniform mat4x4 tm_l2g; uniform mat4x4 tm_l2g_dir; uniform mat4x4 tm_g2s; uniform mat4x4 tm_l2s_per; uniform mat4x4 tm_per; layout(location=0) in vec3 pos; layout(location=1) in vec4 col; layout(location=2) in vec2 txr; layout(location=3) in vec3 tan; layout(location=4) in vec3 bin; layout(location=5) in vec3 nor; out smooth vec3 pixel_pos; out smooth vec4 pixel_col; out smooth vec2 pixel_txr; //out flat mat3 pixel_TBN; out smooth mat3 pixel_TBN; //------------------------------------------------------------------ void main(void) { vec4 p; p.xyz=pos; p.w=1.0; p=tm_l2g*p; pixel_pos=p.xyz; p=tm_g2s*p; gl_Position=p; pixel_col=col; pixel_txr=txr; p.xyz=tan.xyz; p.w=1.0; pixel_TBN[0]=normalize((tm_l2g_dir*p).xyz); p.xyz=bin.xyz; p.w=1.0; pixel_TBN[1]=normalize((tm_l2g_dir*p).xyz); p.xyz=nor.xyz; p.w=1.0; pixel_TBN[2]=normalize((tm_l2g_dir*p).xyz); } //------------------------------------------------------------------

[Fragmento]

//------------------------------------------------------------------ #version 420 core //------------------------------------------------------------------ in smooth vec3 pixel_pos; in smooth vec4 pixel_col; in smooth vec2 pixel_txr; //in flat mat3 pixel_TBN; in smooth mat3 pixel_TBN; uniform sampler2D txr_texture0; uniform sampler2D txr_texture1; uniform sampler2D txr_normal; uniform sampler2D txr_specular; uniform sampler2D txr_light; uniform samplerCube txr_skybox; const int _lights=3; uniform vec3 light_col0=vec3(0.1,0.1,0.1); uniform vec3 light_dir[_lights]= // direction to local star in ellipsoid space { vec3(0.0,0.0,+1.0), vec3(0.0,0.0,+1.0), vec3(0.0,0.0,+1.0), }; uniform vec3 light_col[_lights]= // local star color * visual intensity { vec3(1.0,0.0,0.0), vec3(0.0,1.0,0.0), vec3(0.0,0.0,1.0), }; out layout(location=0) vec4 frag_col; const vec4 v05=vec4(0.5,0.5,0.5,0.5); const bool _blend=false; const bool _reflect=true; //------------------------------------------------------------------ void main(void) { float a=0.0,b,li; vec4 col,blend0,blend1,specul,skybox; vec3 normal; col=(texture2D(txr_normal,pixel_txr.st)-v05)*2.0; // normal/bump maping // normal=pixel_TBN*col.xyz; normal=pixel_TBN[0]; blend0=texture(txr_texture0,pixel_txr.st); blend1=texture(txr_texture1,pixel_txr.st); specul=texture(txr_specular,pixel_txr.st); skybox=texture(txr_skybox,normal); if (_blend) { a=blend1.a; blend0*=1.0-a; blend1*=a; blend0+=blend1; blend0.a=a; } col.xyz=light_col0; col.a=0.0; li=0.0; // normal shading (aj s bump mapingom) for (int i=0;i<_lights;i++) { b=dot(light_dir[i],normal.xyz); if (b<0.0) b=0.0; // b*=specul.r; li+=b; col.xyz+=light_col[i]*b; } col*=blend0; if (li<=0.1) { blend0=texture2D(txr_light,pixel_txr.st); blend0*=1.0-a; blend0.a=a; col+=blend0; } if (_reflect) col+=skybox*specul.r; col*=pixel_col; if (col.r<0.0) col.r=0.0; if (col.g<0.0) col.g=0.0; if (col.b<0.0) col.b=0.0; a=0.0; if (a<col.r) a=col.r; if (a<col.g) a=col.g; if (a<col.b) a=col.b; if (a>1.0) { a=1.0/a; col.r*=a; col.g*=a; col.b*=a; } frag_col=col; } //------------------------------------------------------------------

Estos códigos fuente son un poco antiguos y combinan diferentes cosas para una aplicación específica

Entonces extraiga solo lo que necesita de él. Si está confundido con los nombres de las variables, coménteme ...

  • tm_ significa matriz de transformación
  • l2g significa sistema de coordenadas local para transformar el sistema de coordenadas global
  • dir significa que la transformación cambia de dirección (el desplazamiento es 0,0,0)
  • g2s significa global para la pantalla ...
  • per es perspectiva transformar ...

El registro de compilación GLSL

Debe obtener su contenido programáticamente después de compilar el sombreador (¡no la aplicación!). Lo hago llamando a la función glGetShaderInfoLog para cada sombreador, programa que uso ...

[Notas]

Algunos controladores optimizan las variables "no utilizadas". Como puede ver en la imagen, txr_texture1 no se encuentra incluso si el sombreador de fragmentos lo tiene en el código, pero la combinación no se usa en esta aplicación, por lo que el controlador la eliminó por sí sola ...

Los registros de sombreado pueden mostrarle mucho (errores de sintaxis, advertencias ...)

Hay pocos IDE GLSL para facilitar el sombreado, pero prefiero el mío porque puedo usar directamente el código de la aplicación de destino. El mío se ve así:

cada ventana txt es una fuente de sombreador (vértice, fragmento, ...) la parte inferior derecha es el portapapeles, la parte superior izquierda es el registro del sombreador después de la última compilación y la parte inferior izquierda es la vista previa. Logré codificarlo como el IDE de estilo Borland (con las teclas también y el resaltado de sintaxis). Los otros IDE que vi son similares (diferentes colores de grueso :)) de todos modos si quieres jugar con la aplicación de descarga del sombreador o hacerlo tú mismo ayudará mucho ...

También podría haber un problema con la creación de TBN

Debe verificar visualmente si los vectores TBN (tangente, binormal, normal) corresponden a la superficie del objeto dibujando líneas de colores en cada posición de vértice. Solo para estar seguro ... algo como esto: