使用VBOS时,如何将法向矢量信息传输到OpenGL ES 2.0?
更新:看来,这些东西大部分现在都消失了。 我认为在OpenGL ES 2.0中正确使用光照的方法是编写自己的着色器,以任何希望的方式传递法线,然后在着色器中进行光照。 尤其是,根据OpenGL ES 2.0文档,不再有glMaterialFv,glLightFv等(更不用说glNormalPointer和朋友了。)我认为这是为我编译的原因是因为这些东西在iOS中由GLKit提供,尽管显然他们并没有像现成的替代品那样真正起作用。 但是,GLKit提供了一些标准着色器来模拟OpenGL ES 1.1中的照明功能。
如果有人有任何进一步的信息,我很感激,但我认为这是答案。
我是OpenGL的新手,对于任何混淆事先抱歉。 我在iOS上使用OpenGL ES 2.0。 我在互联网上找到的许多例子似乎都过时了。 例如,glBegin(GL_POLYGON)方法似乎不推荐使用,所以我不认为我可以像大多数较老的示例那样使用glNormal3f。
我从Ray Wenderlich的漂亮教程开始,并将其与我正在构建的游戏集成,成功渲染了一些房间的基本几何图形。 现在我只想添加照明。 我不确定什么不起作用,但我怀疑它与法线有关。
我做了一个混淆的尝试来启用GL_LIGHT0,很大程度上取自OpenGL文档。
//* Some attempts at lighting
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_shininess[] = { 50.0 };
GLfloat light0_position[] = { 0.0, 0.0, 7.99, 0.0 };
GLfloat light0_ambience[] = { 0.2, 0.2, 0.2, 1.0 };
GLfloat light0_specular[] = { 1.0, 1.0, 1.0, 1.0 };
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambience);
glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
glShadeModel(GL_SMOOTH);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
//*/
glEnable(GL_DEPTH_TEST);
我使用VBOS将顶点位置和颜色传递给一对简单的着色器。 以下是来自教程:
_positionSlot = glGetAttribLocation(programHandle, "Position");
_colorSlot = glGetAttribLocation(programHandle, "SourceColor");
然后在render:方法中(我已经修改了顶点结构以在位置和颜色位置之间包含法线)。
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE,
sizeof(Vertex), 0);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE,
sizeof(Vertex), (GLvoid*) (sizeof(float) * 6));
所有这些工作都很好,除了照明。 我已经计算并重新计算了我的法线。 对于平行于X轴和Y轴的垂直矩形墙,这是微不足道的。 它们是绑定到GL_ARRAY_BUFFER的缓冲区的一部分,以及位置和颜色信息。
我曾多次尝试使用glNormalPointer:
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, sizeof(Vertex), (GLvoid*)(sizeof(float)*3));
现在教程中的顶点结构是:
typedef struct {
float Position[3];
float Normal[3];
float Color[4];
} Vertex;
上面的调用成功,但不会出现灯光效果。 有些消息来源表示我也应该使用glVertexAttribPointer作为法线。 为此,我修改了教程的顶点着色器:
attribute vec4 Position;
attribute vec4 SourceColor;
attribute vec3 Normal;
varying vec4 DestinationColor;
uniform mat4 Projection;
uniform mat4 Modelview;
void main(void) {
DestinationColor = SourceColor;
gl_Position = Projection * Modelview * Position;
}
并添加了我认为可以使用Normal变量的调用(尽管我不确定OpenGL如何知道如何处理它):
// just before glLinkProgram()
glBindAttribLocation(programHandle, 1, "Normal");
GLuint _normalSlot = glGetAttribLocation(programHandle, "Normal");
glVertexAttribPointer(_normalSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(float)*3));
我注意到,无论我将Normal变量放在GLSL文件的哪个位置,glBindAttribLocation总是对该属性失败,并且glGetAttribLocation始终对该属性返回-1。 (我可以使用glBindAttribLocation成功更改SourceColor属性的位置,但它不会接受普通。)旧版本的OpenGL / GLSL中曾经有一个gl_Normal变量,但显然已经不再。
我不知所措,只是继续尝试发生在我身上的任何事情。 我的下一步将是迈向glInterleavedArrays。 有很多移动部件,很难找到问题。 这可能是因为我的法线一直很好,而且光线有问题。 除了照明,有什么方法可以确认你的法线是正确的吗? 或者,如果法线错误,我是否应该从光明中看到任何东西?
所以,对于这篇文章的长度和困惑我表示歉意,但是对这种情况下如何指定法线的任何详细解释都是值得欢迎的。 我反复抨击现在在OpenGL ES 2.0中有所不同,但从来没有任何详细的例子。 提前致谢。
自发布以来,我学到了很多东西,并认识到它从未真正得到过正确的回答。 更新是正确的,但值得多解释一下,因为我从来没有在任何地方看到过很好的解释。 这是一个简短的例子,可以从一个具体的具体例子中受益,但希望它能够达到要点。
您通常将法线向量作为VBO中顶点属性的三元组来传输。 如果您使用的是纹理,您将在代码中定义一个包含最少12个浮点属性的顶点结构:顶点的三个空间坐标(xyz),顶点的法向矢量的三个分量,四个颜色分量(rgba)以及纹理坐标的两个分量。 根据您的照明模型,您可以根据硬件限制使用自定义的更多属性,直至GL_MAX_VERTEX_ATTRIBS。
这取决于你如何布置结构,因为你是将要进行所有照明计算的人; 这些对OpenGL ES 2.0没有任何意义。 您必须构建计算每个像素颜色的GLSL顶点和片段着色器程序。 您可以为您定义的每个属性矢量调用glVertexAttribPointer一次,这会导致将属性矢量以您指定的名称传递给顶点着色器。 您可以使用变化将它从顶点着色器传递给片段着色器。 片段着色器中的属性值将通过线性插值来确定。
您通常还会通过许多制服并提供更多照明参数。 对于任何不同于一个顶点的任何事物,如光线的位置或强度或光泽等物质属性,请使用制服。 使用顶点属性来查看模型中的任何变化。
大部分的魔法都应该发生在片段着色器中。 使用法线矢量的最简单的照明效果是漫反射照明,您可以使用如下所示的片段着色器进行制作:
varying lowp vec4 FragmentPosition;
varying lowp vec3 FragmentNormal;
varying lowp vec4 FragmentColor;
uniform lowp vec3 LightPosition;
uniform lowp float LightIntensity;
void main() {
// .xyz makes a vec3 out of a vec4
lowp vec3 inLightFrame = FragmentPosition.xyz - LightPosition;
lowp float distance = length(inLightFrame);
// inverse square dependence of intensity
gl_FragColor = max(0.0, -dot(inLightFrame, normalize(FragmentNormal)))
/ distance / distance * LightIntensity * FragmentColor;
}
这假设LightPosition统一矢量在软件和顶点着色器中设置,如下所示:
attribute vec4 Position;
attribute vec3 Normal;
attribute vec4 Color;
varying vec4 FragmentPosition;
varying vec4 FragmentNormal;
varying vec4 FragmentColor;
void main() {
FragmentPosition = Position;
FragmentNormal = normalize(Normal);
FragmentColor = Color;
}
另外,还会有一些对glVertexAttribPointer的调用来定义Position,Normal和Color,例如:
glVertexAttribPointer(glGetAttribLocation(programHandle, "Position"), 3, GL_FLOAT,
GL_FALSE, sizeof(Vertex), (GLvoid*(sizeof(float)*0));
glVertexAttribPointer(glGetAttribLocation(programHandle, "Normal"), 3, GL_FLOAT,
GL_FALSE, sizeof(Vertex), (GLvoid*(sizeof(float)*3));
glVertexAttribPointer(glGetAttribLocation(programHandle, "Color"), 4, GL_FLOAT,
GL_FALSE, sizeof(Vertex), (GLvoid*(sizeof(float)*6));
这假定一个结构像
typedef struct {
float Position[3];
float Normal[3];
GLubyte Color[4];
} Vertex;
这个微不足道的例子假定单位强度的白光。 您可能需要更多的灯光,并且您可能需要为每个指定红色,绿色和蓝色强度。 此示例忽略材质属性,环境和镜面光照以及阴影。 但这是你在OpenGL ES 2.0中处理法向量的方式。
链接地址: http://www.djcxy.com/p/52427.html上一篇: How do you transmit Normal vector information to OpenGL ES 2.0 when using VBOS?