GLSL/OpenGL 2.1:使用制服的镜面照明
因此,我开始寻求在不使用 OpenGL 照明系统的情况下实现出色的照明。我已经成功实现了 Phong 漫射照明。镜面反射给我带来了麻烦。
我需要知道我正在使用的 OpenGL 常量占用了哪些空间,因为它们似乎被错误转换,并且会导致照明故障。
通过成功加载和运行 Phong 漫反射着色器,我已确认我的 C++ 代码没有问题。然而,C++ 代码可能会向着色器传递无效数据,这是我担心的事情之一。我将粘贴带有注释的着色器以及与着色器直接相关的所有 C++ 代码(尽管我 90% 确定问题出在着色器中)。
在这些图像中,光源是大点,并且显示了轴。 灯光以 y = 0 的角度围绕 icosphere 旋转。
这是漫反射,因此您可以了解模型是什么...... 请注意,我还没有完成逐像素...
这是菲涅尔照明,如源代码所示... 注意被照亮的面如何面向光线,而不是光线和相机之间的某个位置。
这是 Blinn-Phong,我必须将其乘以 30... 再次注意照亮的面如何指向光源,以及我必须将镜面反射系数 (S) 乘以 30 才能实现此
顶点着色器源(从“dirlight.vs”加载)
const int MAXLIGHTS = 4;
uniform bool justcolor = false;
uniform int lightcount;
uniform vec4 lightposs[MAXLIGHTS];
uniform vec4 lightdirs[MAXLIGHTS];
uniform vec4 lightdifs[MAXLIGHTS];
uniform vec4 lightambs[MAXLIGHTS];
//diffuse
vec4 D;
//specular, normaldotlight
float S, NdotL[MAXLIGHTS];
//normal, eyevec, lightvecs, halfvecs
vec3 N, E, L[MAXLIGHTS], H[MAXLIGHTS];
void main() {
//if(lightcount > MAXLIGHTS) lightcount = MAXLIGHTS;
D = vec4(0.0, 0.0, 0.0, 0.0);
S = 0.0;
N = gl_Normal;
E = normalize(vec3(-gl_Vertex));
for(int i = 0; i < lightcount; i++)
{
//calculating direction to light source
L[i] = normalize(vec3(lightposs[i] - gl_Vertex));
//normal dotted with direction to light source
NdotL[i] = max(dot(N, L[i]), 0.0);
//diffuse term, works just fine
D += gl_Color * lightdifs[i] * NdotL[i];
if(NdotL[i] >= 0.0)
{
//halfvector = normalize(lightdir + eyedir)
H[i] = normalize(L[i] + E);
//Blinn-Phong, only lights up faces whose normals
//point directly to the light source for some reason...
//S += max(0.0, dot(H[i], N));
//Fresnel, lights up more than Blinn-Phong
//but the faces still point directly to the light source,
//not somewhere between the lightsource and myself, like they should.
S += pow(max(0.0, dot(reflect(L[i], N), E)), 50.0);
}
else
{
H[i] = vec3(0.0, 0.0, 0.0);
}
}
//currently only showing specular. To show diffuse add D.
gl_FrontColor = justcolor ? gl_Color : vec4(S * 0.3, S * 0.3, S * 0.3, 1.0);
gl_Position = ftransform();
}
片段着色器源(从“dirlight.fs”)
void main()
{
gl_FragColor = gl_Color;
}
摘自 C++ 主初始化...
//class program manages shaders
Program shaders = Program();
//attach a vertex shader, compiled from source in dirlight.vs
shaders.addShaderFile(GL_VERTEX_SHADER, "dirlight.vs");
//attach a fragment shader compiled from source in dirlight.fs
shaders.addShaderFile(GL_FRAGMENT_SHADER, "dirlight.fs");
//link program
shaders.link();
//use program
shaders.use();
//Program::getUniformLoc(const char* name) grabs the location
//of the uniform specified
GLint sTime = shaders.getUniformLoc("time");
GLint lightcount = shaders.getUniformLoc("lightcount");
GLint lightdir = shaders.getUniformLoc("lightdirs");
GLint lightdif = shaders.getUniformLoc("lightdifs");
GLint lightamb = shaders.getUniformLoc("lightambs");
GLint lightpos = shaders.getUniformLoc("lightposs");
GLint justcolor = shaders.getUniformLoc("justcolor");
glUniform1i(justcolor, 0);
glUniform1i(lightcount, 2);
//diffuse light colors
GLfloat lightdifs[] = {1.f, 1.f, 1.f, 1.f,
1.f, 1.f, 1.f, 1.f};
glUniform4fv(lightdif, 2, lightdifs);
glUniform4f(lightamb, 0.4f, 0.4f, 0.4f, 1.f);
摘自 C++ 主循环...
//My lights rotate around the origin, where I have placed an icosphere
GLfloat lightposs[] = {-4 * sinf(newTime), lighth, -4 * cosf(newTime), 0.0f,
-4 * sinf(newTime + M_PI), lighth, -4 * cosf(newTime + M_PI), 0.0f};
glUniform4fv(lightpos, 2, lightposs);
So, I've begun a quest to implement awesome lighting without using OpenGL's lighting system. I've successfully implemented Phong diffuse lighting. Specular is giving me trouble.
I need to know what spaces the OpenGL constants I'm using occupy, because it seems they are mis-transformed, and that it results in lighting glitches.
I have confirmed that there is no problem with my C++ code by successfully loading and running a Phong diffuse shader. The C++ code may, however, be passing invalid data to the shaders, which is one of the things I'm worried about. I will paste my shaders with comments, as well as all C++ code directly pertaining to the shaders (although I'm 90% sure the problem is in the shaders).
In these images, the light sources are large points, and the axes are shown.
The lights are rotating at y = 0 around an icosphere.
Here's the diffuse, so you get an idea what the model is...
Note I haven't done per-pixel yet...
Here's the Fresnel lighting, as shown in source...
Note how the lit faces are facing the light, not somewhere between the light and the camera
Here's the Blinn-Phong, which I had to multiply by 30...
Note again how the lit faces point towards the light source, and also the fact that I had to multiply the Specular factor (S) by 30 to achieve this
Vertex Shader Source (loaded from "dirlight.vs")
const int MAXLIGHTS = 4;
uniform bool justcolor = false;
uniform int lightcount;
uniform vec4 lightposs[MAXLIGHTS];
uniform vec4 lightdirs[MAXLIGHTS];
uniform vec4 lightdifs[MAXLIGHTS];
uniform vec4 lightambs[MAXLIGHTS];
//diffuse
vec4 D;
//specular, normaldotlight
float S, NdotL[MAXLIGHTS];
//normal, eyevec, lightvecs, halfvecs
vec3 N, E, L[MAXLIGHTS], H[MAXLIGHTS];
void main() {
//if(lightcount > MAXLIGHTS) lightcount = MAXLIGHTS;
D = vec4(0.0, 0.0, 0.0, 0.0);
S = 0.0;
N = gl_Normal;
E = normalize(vec3(-gl_Vertex));
for(int i = 0; i < lightcount; i++)
{
//calculating direction to light source
L[i] = normalize(vec3(lightposs[i] - gl_Vertex));
//normal dotted with direction to light source
NdotL[i] = max(dot(N, L[i]), 0.0);
//diffuse term, works just fine
D += gl_Color * lightdifs[i] * NdotL[i];
if(NdotL[i] >= 0.0)
{
//halfvector = normalize(lightdir + eyedir)
H[i] = normalize(L[i] + E);
//Blinn-Phong, only lights up faces whose normals
//point directly to the light source for some reason...
//S += max(0.0, dot(H[i], N));
//Fresnel, lights up more than Blinn-Phong
//but the faces still point directly to the light source,
//not somewhere between the lightsource and myself, like they should.
S += pow(max(0.0, dot(reflect(L[i], N), E)), 50.0);
}
else
{
H[i] = vec3(0.0, 0.0, 0.0);
}
}
//currently only showing specular. To show diffuse add D.
gl_FrontColor = justcolor ? gl_Color : vec4(S * 0.3, S * 0.3, S * 0.3, 1.0);
gl_Position = ftransform();
}
Fragment Shader Source (loaded from "dirlight.fs")
void main()
{
gl_FragColor = gl_Color;
}
Excerpt from C++ main initialization...
//class program manages shaders
Program shaders = Program();
//attach a vertex shader, compiled from source in dirlight.vs
shaders.addShaderFile(GL_VERTEX_SHADER, "dirlight.vs");
//attach a fragment shader compiled from source in dirlight.fs
shaders.addShaderFile(GL_FRAGMENT_SHADER, "dirlight.fs");
//link program
shaders.link();
//use program
shaders.use();
//Program::getUniformLoc(const char* name) grabs the location
//of the uniform specified
GLint sTime = shaders.getUniformLoc("time");
GLint lightcount = shaders.getUniformLoc("lightcount");
GLint lightdir = shaders.getUniformLoc("lightdirs");
GLint lightdif = shaders.getUniformLoc("lightdifs");
GLint lightamb = shaders.getUniformLoc("lightambs");
GLint lightpos = shaders.getUniformLoc("lightposs");
GLint justcolor = shaders.getUniformLoc("justcolor");
glUniform1i(justcolor, 0);
glUniform1i(lightcount, 2);
//diffuse light colors
GLfloat lightdifs[] = {1.f, 1.f, 1.f, 1.f,
1.f, 1.f, 1.f, 1.f};
glUniform4fv(lightdif, 2, lightdifs);
glUniform4f(lightamb, 0.4f, 0.4f, 0.4f, 1.f);
Excerpt from C++ main loop...
//My lights rotate around the origin, where I have placed an icosphere
GLfloat lightposs[] = {-4 * sinf(newTime), lighth, -4 * cosf(newTime), 0.0f,
-4 * sinf(newTime + M_PI), lighth, -4 * cosf(newTime + M_PI), 0.0f};
glUniform4fv(lightpos, 2, lightposs);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的代码中缺少一些重要的内容。首先,您应该将顶点位置和法线转换为眼睛空间。那里的光照计算是最简单的。顶点位置使用模型视图矩阵进行变换,法线使用模型视图的转置逆矩阵进行变换。通常灯光位置位于世界坐标中,因此提供从世界坐标到眼睛坐标的附加矩阵是有意义的。
There are few important things missing from your code. First you should transform vertex position and normal into eye space. Lighting calculations are easiest there. Vertex position transforms using the modelview matrix, the normals transform with the transposed inverse of the modelview. Usually light positions are in world coordinates, so it makes sense to supply an additional matrix from world to eye coordinates.