纹理平面上的 OpenGL 照明不起作用 [英] OpenGL Lighting on texture plane is not working

查看:34
本文介绍了纹理平面上的 OpenGL 照明不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想照亮纹理平面,但这不起作用.实体球体上的光很好,但纹理平面不亮.

)

正在加载纹理.

 sf::Image image;if (!image.loadFromFile(path))返回假;glGenTextures(1, &id);glBindTexture(GL_TEXTURE_2D, id);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,image.getSize().x, image.getSize().y, 0,GL_RGBA, GL_UNSIGNED_BYTE,image.getPixelsPtr());glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

初始化

 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);glClearDepth(1.0f);glEnable(GL_DEPTH_TEST);glDepthFunc(GL_LEQUAL);glShadeModel(GL_SMOOTH);//glEnable(GL_CULL_FACE);glFrontFace(GL_CCW);glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);glutSetCursor(GLUT_CURSOR_NONE);光.Init();camera.SetPin((GLfloat)width/2, (GLfloat)height/2);

显示回调

 adjustPerspective();glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glMatrixMode(GL_MODELVIEW);glLoadIdentity();glEnable(GL_LIGHTING);glPushMatrix();相机.SetLookAt();点亮();//TODO: 显示处理for (auto& obj : display_objs){glPushMatrix();对象->绘制();glPopMatrix();}glPopMatrix();//打印 fps 并交换缓冲区

灯光初始化函数

 glEnable(GL_LIGHTING);glEnable(GL_LIGHT0);glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);glEnable(GL_COLOR_MATERIAL);//设置光照强度和颜色glLightfv(GL_LIGHT0, GL_AMBIENT, qaAmbientLight);glLightfv(GL_LIGHT0, GL_DIFFUSE, qaDiffuseLight);glLightfv(GL_LIGHT0, GL_POSITION, qaLightPosition);glLightfv(GL_LIGHT0, GL_SPECULAR, qaSpecularLight);////////////////////////////////////////////////glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 80.0);//设置截止角度glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, dirVector0);glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 10.0);//设置对焦强度

Light.On() 函数

 glPushMatrix();glTranslatef(2.0, 10.0, 2.0);//glRotatef(90, 1, 0, 0);glLightfv(GL_LIGHT0, GL_POSITION, qaLightPosition);glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, dirVector0);glPopMatrix();glPushMatrix();glDisable(GL_LIGHTING);glTranslatef(2.0, 0.0, 2.0);glRotatef(-90.0, 1.0, 0.0, 0.0);glutWireCone(tan(80.0/180.0 * 3.14159265),10.0,20,20);glEnable(GL_LIGHTING);glPopMatrix();

这是纹理平面绘制功能.

 float tile_x = 0.125;glTranslatef(x, y, z);glEnable(GL_BLEND);glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);glEnable(GL_TEXTURE_2D);glBindTexture(GL_TEXTURE_2D, tex.GetId());glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);glBegin(GL_QUADS);//以下两种情况都不起作用.glNormal3f(0, -1, 0);glNormal3f(0, 1, 0);glTexCoord2f(0.0, 0.0);glVertex3f(0, 0, 0);glTexCoord2f(height*tile_x, 0.0);glVertex3f(0, 0, 宽度);glTexCoord2f(高度*tile_x,宽度*tile_x);glVertex3f(height, 0, width);glTexCoord2f(0.0, 宽度*tile_x);glVertex3f(height, 0, 0);glEnd();glDisable(GL_TEXTURE_2D);glDisable(GL_BLEND);

我改变了矢量方向,改变了glTexEnvf属性,改变了代码的顺序,但没有修复错误.我认为我的代码中有一个基本错误,但我找不到它.为什么会发生这种情况,我该如何解决?

解决方案

我想照亮纹理平面,但这不起作用.实体球体上的光很好,但纹理平面不亮.

这是由 OpenGL 标准光模型的 Gouraud Shading 模型引起的问题.虽然 Phong shading 通常意味着技术,它对每个片段进行光计算,在 Gouraud Shading,光计算是按顶点完成的.根据图元上片段的重心坐标对计算出的光进行插值.

这意味着在您的情况下,灯光是针对地面四边形的角计算的.这种计算出的光被插入到中间的所有片段中.拐角处的法向量与光向量的角度趋于 90°.因此,整个地面四边形看起来几乎没有灯光.

由于光是按顶点计算的,所以光是针对比四边形的 4 个角更多的位置计算的,质量会提高.请注意,球体上的光线看起来几乎是完美的,因为球体由围绕其形状的许多顶点组成.

试试下面的代码,它将四边形分割成瓦片:

int tile = 5;浮动 u_max = 高度 * tile_x;浮动 v_max = 宽度*tile_xglBegin(GL_QUADS);glNormal3f(0, 1, 0);for (int x=0; x 

当然,您也可以编写自己的着色器并实现每个片段照明.但是已弃用的固定功能管道 OpenGL 标准光照模型不支持每个片段光照.

查看 WebGL 示例中的差异:

(function loadscene() {var resize, gl, gouraudDraw, phongDraw, vp_size;var bufSphere = {};函数渲染(delteMS){var shading = document.getElementById( "shading" ).value;var shininess = document.getElementById( "shininess" ).value;varambientCol = [0.2, 0.2, 0.2];vardiffuseCol = [0.6, 0.6, 0.6];var specularCol = [0.8, 0.8, 0.8];相机创建();Camera.vp = vp_size;gl.enable(gl.DEPTH_TEST);gl.clearColor( 0.0, 0.0, 0.0, 1.0 );gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );gl.disable(gl.CULL_FACE);var progDraw = shading == 0 ?gouraudDraw : phongDraw;;//设置绘制着色器ShaderProgram.Use( progDraw.prog );ShaderProgram.SetUniformM44( progDraw.prog, "u_projectionMat44", Camera.Perspective());ShaderProgram.SetUniformM44( progDraw.prog, "u_viewMat44", Camera.LookAt());ShaderProgram.SetUniformF3( progDraw.prog, "u_lightSource.lightPos", [0.0, 0.0, 0.25] )ShaderProgram.SetUniformF3( progDraw.prog, "u_lightSource.ambient",ambientCol)ShaderProgram.SetUniformF3( progDraw.prog, "u_lightSource.diffuse",diffuseCol)ShaderProgram.SetUniformF3( progDraw.prog, "u_lightSource.specular", specularCol )ShaderProgram.SetUniformF1( progDraw.prog, "u_lightSource.shininess", shininess )var modelMat = IdentityMat44()modelMat = RotateAxis(modelMat, -1.5, 0);modelMat = RotateAxis(modelMat, CalcAng(delteMS, 17.0), 1);ShaderProgram.SetUniformM44( progDraw.prog, "u_modelMat44", modelMat );//绘制场景VertexBuffer.Draw( bufSphere );请求动画帧(渲染);}函数调整大小(){//vp_size = [gl.drawingBufferWidth, gl.drawingBufferHeight];vp_size = [window.innerWidth, window.innerHeight]canvas.width = vp_size[0];canvas.height = vp_size[1];gl.viewport(0, 0, vp_size[0], vp_size[1]);}函数 initScene() {canvas = document.getElementById("canvas");gl = canvas.getContext( "experimental-webgl" );如果(!gl)返回空;gouraudDraw = {}gouraudDraw.prog = ShaderProgram.Create([ { 来源:gouraud-shader-vs",舞台:gl.VERTEX_SHADER },{ 来源:gouraud-shader-fs",舞台:gl.FRAGMENT_SHADER }],[ "u_projectionMat44", "u_viewMat44", "u_modelMat44","u_lightSource.lightDir", "u_lightSource.ambient", "u_lightSource.diffuse", "u_lightSource.specular", "u_lightSource.shininess", ] );如果( gouraudDraw.prog == 0 )返回;gouraudDraw.inPos = gl.getAttribLocation( gouraudDraw.prog, "inPos" );gouraudDraw.inNV = gl.getAttribLocation( gouraudDraw.prog, "inNV" );gouraudDraw.inCol = gl.getAttribLocation( gouraudDraw.prog, "inCol" );phongDraw = {}phongDraw.prog = ShaderProgram.Create([ { 来源:phong-shader-vs",阶段:gl.VERTEX_SHADER },{ 来源:phong-shader-fs",阶段:gl.FRAGMENT_SHADER }],[ "u_projectionMat44", "u_viewMat44", "u_modelMat44","u_lightSource.lightDir", "u_lightSource.ambient", "u_lightSource.diffuse", "u_lightSource.specular", "u_lightSource.shininess", ] );如果( phongDraw.prog == 0 )返回;phongDraw.inPos = gl.getAttribLocation( phongDraw.prog, "inPos" );phongDraw.inNV = gl.getAttribLocation( phongDraw.prog, "inNV" );phongDraw.inCol = gl.getAttribLocation( phongDraw.prog, "inCol" );//创建立方体var layer_size = 16,circum_size = 32;var rad_circum = 1.0;var rad_tube = 0.5;var sphere_pts = [-1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 1.0, 0.0, -1.0, 1.0, 0.0];var sphere_nv = [0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0];var sphere_col = [0.8, 0.6, 0.3, 0.8, 0.6, 0.3, 0.8, 0.6, 0.3, 0.8, 0.6, 0.3];var sphere_inx = [0, 1, 2, 0, 2, 3];bufSphere = VertexBuffer.Create([ { 数据 : sphere_pts, attrSize : 3, attrLoc : gouraudDraw.inPos },{数据:sphere_nv,attrSize:3,attrLoc:gouraudDraw.inNV},{数据:sphere_col,attrSize:3,attrLoc:gouraudDraw.inCol}],球体_inx );window.onresize = 调整大小;调整大小();请求动画帧(渲染);}函数分数( val ) {返回 val - Math.trunc( val );}函数 CalcAng( deltaTime, intervall ) {return Fract(deltaTime/(1000*interval)) * 2.0 * Math.PI;}函数 CalcMove( deltaTime, intervall, range ) {var pos = self.Fract( deltaTime/(1000*intervall) ) * 2.0var pos = pos <1.0 ?位置:(2.0-位置)返回范围[0] + (范围[1] - 范围[0]) * pos;}函数椭圆位置(a,b,angRag){var a_b = a * a - b * bvar ea = (a_b <= 0) ?0 : Math.sqrt( a_b );var eb = (a_b >= 0) ?0 : Math.sqrt( -a_b );返回 [ a * Math.sin( angRag ) - ea, b * Math.cos( angRag ) - eb, 0 ];}glArrayType = typeof Float32Array !="undefined" ?Float32Array : ( typeof WebGLFloatArray != "undefined" ? WebGLFloatArray : Array );功能 IdentityMat44() {var m = new glArrayType(16);米[0] = 1;m[1] = 0;m[2] = 0;m[3] = 0;m[4] = 0;米[5] = 1;米[6] = 0;米[7] = 0;米[8] = 0;米[9] = 0;米[10] = 1;米[11] = 0;米[12] = 0;m[13] = 0;m[14] = 0;米[15] = 1;返回 m;};函数旋转轴(matA,angRad,轴){var aMap = [ [1, 2], [2, 0], [0, 1] ];var a0 = aMap[axis][0], a1 = aMap[axis][1];var sinAng = Math.sin(angRad), cosAng = Math.cos(angRad);var matB = new glArrayType(16);for ( var i = 0; i <16; ++ i ) matB[i] = matA[i];for ( var i = 0; i <3; ++ i ) {matB[a0*4+i] = matA[a0*4+i] * cosAng + matA[a1*4+i] * sinAng;matB[a1*4+i] = matA[a0*4+i] * -sinAng + matA[a1*4+i] * cosAng;}返回 matB;}function Cross( a, b ) { return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2],a[0] * b[1] - a[1] * b[0], 0.0 ];}function Dot( a, b ) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];}函数归一化( v ) {var len = Math.sqrt( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] );返回 [ v[0]/len, v[1]/len, v[2]/len ];}var 相机 = {};Camera.create = function() {this.pos = [0, 2, 0.0];this.target = [0, 0, 0];this.up = [0, 0, 1];this.fov_y = 90;this.vp = [800, 600];this.near = 0.5;this.far = 100.0;}Camera.Perspective = function() {var fn = this.far + this.near;var f_n = this.far - this.near;var r = this.vp[0]/this.vp[1];var t = 1/Math.tan( Math.PI * this.fov_y/360 );var m = IdentityMat44();m[0] = t/r;m[1] = 0;m[2] = 0;m[3] = 0;m[4] = 0;m[5] = t;米[6] = 0;米[7] = 0;米[8] = 0;米[9] = 0;m[10] = -fn/f_n;m[11] = -1;米[12] = 0;m[13] = 0;m[14] = -2 * this.far * this.near/f_n;米[15] = 0;返回 m;}Camera.LookAt = 函数(){var mz = Normalize( [ this.pos[0]-this.target[0], this.pos[1]-this.target[1], this.pos[2]-this.target[2] ] );var mx = Normalize( Cross( this.up, mz ) );var my = Normalize( Cross( mz, mx ) );var tx = Dot( mx, this.pos );var ty = Dot( my, this.pos );var tz = Dot( [-mz[0], -mz[1], -mz[2]], this.pos );var m = IdentityMat44();m[0] = mx[0];米[1] = 我的[0];m[2] = mz[0];m[3] = 0;m[4] = mx[1];米[5] = 我的[1];m[6] = mz[1];米[7] = 0;m[8] = mx[2];米[9] = 我的[2];m[10] = mz[2];米[11] = 0;m[12] = tx;m[13] = ty;m[14] = tz;米[15] = 1;返回 m;}var ShaderProgram = {};ShaderProgram.Create = 函数(着色器列表){var shaderObjs = [];for ( var i_sh = 0; i_sh < shaderList.length; ++ i_sh ) {var shderObj = this.CompileShader( shaderList[i_sh].source, shaderList[i_sh].stage);如果(shderObj == 0)返回0;shaderObjs.push( shderObj );}var progObj = this.LinkProgram( shaderObjs )如果(progObj != 0){progObj.attribIndex = {};var noOfAttributes = gl.getProgramParameter( progObj, gl.ACTIVE_ATTRIBUTES );for ( var i_n = 0; i_n 

html,body {高度:100%;宽度:100%;边距:0;溢出:隐藏;}#gui {位置:绝对;顶部:0;左:0;}

<script id="gouraud-shader-fs" type="x-shader/x-fragment">精密中等浮点数;不同的 vec3 vertPos;不同的 vec3 vertNV;不同的 vec3 vertCol;无效主(){gl_FragColor = vec4(vertCol, 1.0);}<script id="phong-shader-vs" type="x-shader/x-vertex">精密中等浮点数;属性 vec3 inPos;属性 vec3 inNV;属性 vec3 inCol;不同的 vec3 vertPos;不同的 vec3 vertNV;不同的 vec3 vertCol;统一 mat4 u_projectionMat44;统一 mat4 u_viewMat44;统一 mat4 u_modelMat44;无效主(){vec3 modelNV = mat3( u_modelMat44 ) * normalize( inNV );vertNV = mat3( u_viewMat44 ) * modelNV;vertCol = inCol;vec4 modelPos = u_modelMat44 * vec4( inPos, 1.0 );vec4 viewPos = u_viewMat44 * modelPos;vertPos = viewPos.xyz/viewPos.w;gl_Position = u_projectionMat44 * viewPos;}<script id="phong-shader-fs" type="x-shader/x-fragment">精密中等浮点数;不同的 vec3 vertPos;不同的 vec3 vertNV;不同的 vec3 vertCol;结构体 TLightSource{vec3 lightPos;vec3 环境;vec3 漫反射;vec3 镜面;漂浮光泽;};统一 TLightSource u_lightSource;vec3 Light( vec3 eyeV, vec3 N, vec3 P ){vec3 lightCol = u_lightSource.ambient;vec3 L = 标准化(u_lightSource.lightPos - P);浮点 NdotL = max( 0.0, dot( N, L ) );lightCol += NdotL * u_lightSource.diffuse;vec3 H = 归一化(eyeV + L);浮点 NdotH = max( 0.0, dot( N, H ) );浮动 kSpecular = ( u_lightSource.shininess + 2.0 ) * pow( NdotH, u_lightSource.shininess )/( 2.0 * 3.14159265 );lightCol += kSpecular * u_lightSource.specular;返回 lightCol;}无效主(){vec3 eyeV = 标准化(-vertPos);vec3 normalV = normalize(vertNV) * 符号(vertNV.z);vec3 color = vertCol * Light( eyeV, normalV, vertPos );gl_FragColor = vec4( 颜色, 1.0 );}<form id="gui" name="inputs"><table><tr><td><font color= #CCF>阴影:</font></td><td><select id="shading">><option value="0">Gouraud</option><option value="1">Phong</option></选择></td></tr><tr><td><font color= #CCF>光泽度:</font></td><td><input type="range" id="shininess" min="0" max="100" value="10"/></td></tr></table></form><canvas id="canvas" style="border: none;"width="100%" height="100%"></canvas>

I want to light to the texture plane but this is not work. Light on solid sphere is very well, but texture plane is not light.

Whole Image

Lighting on solid-sphere is working well.

But, lighting on texture plane is not working. (GL_DECAL, GL_REPLACE; I also tried GL_MODULATE)

This is a snippet of my rendering code. (Whole code on GitHub)

Loading texture.

  sf::Image image;

  if (!image.loadFromFile(path))
    return false;
  glGenTextures(1, &id);
  glBindTexture(GL_TEXTURE_2D, id);

  glTexImage2D(
    GL_TEXTURE_2D, 0, GL_RGBA,
    image.getSize().x, image.getSize().y, 0,
    GL_RGBA, GL_UNSIGNED_BYTE,
    image.getPixelsPtr()
  );

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

Initialize

  glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  glClearDepth(1.0f);
  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LEQUAL);
  glShadeModel(GL_SMOOTH);
  //glEnable(GL_CULL_FACE);
  glFrontFace(GL_CCW);
  glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
  glutSetCursor(GLUT_CURSOR_NONE);
  light.Init();

  camera.SetPin((GLfloat)width / 2, (GLfloat)height/2);

Display Callback

  adjustPerspective();

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glEnable(GL_LIGHTING);

  glPushMatrix();
  camera.SetLookAt();
  light.On();

  // TODO: dsiplay processing
  for (auto& obj : display_objs)
  {
    glPushMatrix();
    obj->Draw();
    glPopMatrix();
  }
  glPopMatrix();

  // print fps and swap buffers

Light Initialize Function

  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
  glEnable(GL_COLOR_MATERIAL);

  // Set lighting intensity and color
  glLightfv(GL_LIGHT0, GL_AMBIENT, qaAmbientLight);
  glLightfv(GL_LIGHT0, GL_DIFFUSE, qaDiffuseLight);
  glLightfv(GL_LIGHT0, GL_POSITION, qaLightPosition);
  glLightfv(GL_LIGHT0, GL_SPECULAR, qaSpecularLight);
  ////////////////////////////////////////////////

  glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 80.0);// set cutoff angle
  glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, dirVector0);
  glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 10.0); // set focusing strength

Light.On() Function

  glPushMatrix();
  glTranslatef(2.0, 10.0, 2.0);
  //glRotatef(90, 1, 0, 0);
  glLightfv(GL_LIGHT0, GL_POSITION, qaLightPosition);
  glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, dirVector0);
  glPopMatrix();

  glPushMatrix();
  glDisable(GL_LIGHTING);
  glTranslatef(2.0, 0.0, 2.0);
  glRotatef(-90.0, 1.0, 0.0, 0.0);
  glutWireCone(tan(80.0 / 180.0 * 3.14159265),10.0,20,20);
  glEnable(GL_LIGHTING);
  glPopMatrix();

And this is texture plane draw function.

  float tile_x = 0.125;

  glTranslatef(x, y, z);

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, tex.GetId());
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

  glBegin(GL_QUADS);
    // Both of the following cases not work.
    glNormal3f(0, -1, 0);
    glNormal3f(0, 1, 0);
    glTexCoord2f(0.0, 0.0); glVertex3f(0, 0, 0);
    glTexCoord2f(height*tile_x, 0.0); glVertex3f(0, 0, width);
    glTexCoord2f(height*tile_x, width*tile_x); glVertex3f(height, 0, width);
    glTexCoord2f(0.0, width*tile_x); glVertex3f(height, 0, 0);
  glEnd();

  glDisable(GL_TEXTURE_2D);
  glDisable(GL_BLEND);

I changed the vector direction, changed the glTexEnvf attribute, changed the order of the code, but did not fix the error. I think there is a fundamental error in my code, but I can not find it. Why is this happening, and how do I fix it?

解决方案

I want to light to the texture plane but this is not work. Light on solid sphere is very well, but texture plane is not light.

This is an issue caused by the Gouraud Shading model of the OpenGLs standard light model. While Phong shading in common means the technique, which does the light calculations per fragment, at Gouraud Shading, the light calculations are done per vertex. The calculated light is interpolated according to the Barycentric coordinate of the fragment on the primitive.

This means that in your case the light is calculated for the corners of the ground quad. This so calculated light is interpolated for all the fragments in between. The angel of the normal vector at the corners to the light vector tends to 90°. Because of that the entire ground quad looks almost unlit.

Since the light is calculated per vertex, then the light is calculated for more positions than the the 4 corners of the quad and the quality increases. Note, the light on the spheres looks almost perfect, because a sphere consists of a lot of vertices around its shape.

Try the following code, which splits the quad into tiles:

int   tiles = 5;
float u_max = height*tile_x;
float v_max = width*tile_x

glBegin(GL_QUADS);
glNormal3f(0, 1, 0);

for (int x=0; x < tiles; ++x)
{
    for (int y=0; y < tiles; ++y)
    {
        x0 = (float)x/(float)tiles;
        x1 = (float)(x+1)/(float)tiles;
        y0 = (float)y/(float)tiles;
        y1 = (float)(y+1)/(float)tiles;

        glTexCoord2f(u_max*x0, v_max*y0);  glVertex3f(height*x0, 0, widht*y0);
        glTexCoord2f(u_max*x1, v_max*y0);  glVertex3f(height*x0, 0, widht*y1);
        glTexCoord2f(u_max*x1, v_max*y1);  glVertex3f(height*x1, 0, widht*y1);
        glTexCoord2f(u_max*x0, v_max*y1);  glVertex3f(height*x1, 0, widht*y0);
    }
}
glEnd();

Of course you can also write your own shader and implement per fragment lighting. But the deprecated fixed function pipeline OpenGL standard light model does not support per fragment lighting.

See the difference in the WebGL example:

(function loadscene() {

var resize, gl, gouraudDraw, phongDraw, vp_size;
var bufSphere = {};

function render(delteMS){

    var shading = document.getElementById( "shading" ).value;
    var shininess = document.getElementById( "shininess" ).value;
    var ambientCol = [0.2, 0.2, 0.2];
    var diffuseCol = [0.6, 0.6, 0.6];
    var specularCol = [0.8, 0.8, 0.8];

    Camera.create();
    Camera.vp = vp_size;
        
    gl.enable( gl.DEPTH_TEST );
    gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
    gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );

    gl.disable(gl.CULL_FACE);
    
    
    var progDraw = shading == 0 ? gouraudDraw : phongDraw;;
    // set up draw shader
    ShaderProgram.Use( progDraw.prog );
    ShaderProgram.SetUniformM44( progDraw.prog, "u_projectionMat44", Camera.Perspective() );
    ShaderProgram.SetUniformM44( progDraw.prog, "u_viewMat44", Camera.LookAt() );
    ShaderProgram.SetUniformF3( progDraw.prog, "u_lightSource.lightPos", [0.0, 0.0, 0.25] )
    ShaderProgram.SetUniformF3( progDraw.prog, "u_lightSource.ambient", ambientCol )
    ShaderProgram.SetUniformF3( progDraw.prog, "u_lightSource.diffuse", diffuseCol )
    ShaderProgram.SetUniformF3( progDraw.prog, "u_lightSource.specular", specularCol )
    ShaderProgram.SetUniformF1( progDraw.prog, "u_lightSource.shininess", shininess )
    var modelMat = IdentityMat44()
    modelMat = RotateAxis( modelMat, -1.5, 0 );
    modelMat = RotateAxis( modelMat, CalcAng( delteMS, 17.0 ), 1 );
    ShaderProgram.SetUniformM44( progDraw.prog, "u_modelMat44", modelMat );
    
    // draw scene
    VertexBuffer.Draw( bufSphere );
   
    requestAnimationFrame(render);
}

function resize() {
    //vp_size = [gl.drawingBufferWidth, gl.drawingBufferHeight];
    vp_size = [window.innerWidth, window.innerHeight]
    canvas.width = vp_size[0];
    canvas.height = vp_size[1];
    gl.viewport( 0, 0, vp_size[0], vp_size[1] );
}

function initScene() {

    canvas = document.getElementById( "canvas");
    gl = canvas.getContext( "experimental-webgl" );
    if ( !gl )
      return null;

    gouraudDraw = {}
    gouraudDraw.prog = ShaderProgram.Create( 
      [ { source : "gouraud-shader-vs", stage : gl.VERTEX_SHADER },
        { source : "gouraud-shader-fs", stage : gl.FRAGMENT_SHADER }
      ],
      [ "u_projectionMat44", "u_viewMat44", "u_modelMat44", 
        "u_lightSource.lightDir", "u_lightSource.ambient", "u_lightSource.diffuse", "u_lightSource.specular", "u_lightSource.shininess", ] );
    if ( gouraudDraw.prog == 0 )
      return;  
    gouraudDraw.inPos = gl.getAttribLocation( gouraudDraw.prog, "inPos" );
    gouraudDraw.inNV  = gl.getAttribLocation( gouraudDraw.prog, "inNV" );
    gouraudDraw.inCol = gl.getAttribLocation( gouraudDraw.prog, "inCol" );

    phongDraw = {}
    phongDraw.prog = ShaderProgram.Create( 
      [ { source : "phong-shader-vs", stage : gl.VERTEX_SHADER },
        { source : "phong-shader-fs", stage : gl.FRAGMENT_SHADER }
      ],
      [ "u_projectionMat44", "u_viewMat44", "u_modelMat44", 
        "u_lightSource.lightDir", "u_lightSource.ambient", "u_lightSource.diffuse", "u_lightSource.specular", "u_lightSource.shininess", ] );
    if ( phongDraw.prog == 0 )
      return;
    phongDraw.inPos = gl.getAttribLocation( phongDraw.prog, "inPos" );
    phongDraw.inNV  = gl.getAttribLocation( phongDraw.prog, "inNV" );
    phongDraw.inCol = gl.getAttribLocation( phongDraw.prog, "inCol" );
    
    // create cube
    var layer_size = 16, circum_size = 32;
    var rad_circum = 1.0;
    var rad_tube = 0.5;
    var sphere_pts = [-1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 1.0, 0.0, -1.0, 1.0, 0.0];
    var sphere_nv  = [0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0];
    var sphere_col = [0.8, 0.6, 0.3, 0.8, 0.6, 0.3, 0.8, 0.6, 0.3, 0.8, 0.6, 0.3];
    var sphere_inx = [0, 1, 2, 0, 2, 3];
    bufSphere = VertexBuffer.Create(
    [ { data : sphere_pts, attrSize : 3, attrLoc : gouraudDraw.inPos },
      { data : sphere_nv, attrSize : 3, attrLoc : gouraudDraw.inNV },
      { data : sphere_col, attrSize : 3, attrLoc : gouraudDraw.inCol } ],
      sphere_inx );
      
    window.onresize = resize;
    resize();
    requestAnimationFrame(render);
}

function Fract( val ) { 
    return val - Math.trunc( val );
}
function CalcAng( deltaTime, intervall ) {
    return Fract( deltaTime / (1000*intervall) ) * 2.0 * Math.PI;
}
function CalcMove( deltaTime, intervall, range ) {
    var pos = self.Fract( deltaTime / (1000*intervall) ) * 2.0
    var pos = pos < 1.0 ? pos : (2.0-pos)
    return range[0] + (range[1] - range[0]) * pos;
}    
function EllipticalPosition( a, b, angRag ) {
    var a_b = a * a - b * b
    var ea = (a_b <= 0) ? 0 : Math.sqrt( a_b );
    var eb = (a_b >= 0) ? 0 : Math.sqrt( -a_b );
    return [ a * Math.sin( angRag ) - ea, b * Math.cos( angRag ) - eb, 0 ];
}

glArrayType = typeof Float32Array !="undefined" ? Float32Array : ( typeof WebGLFloatArray != "undefined" ? WebGLFloatArray : Array );

function IdentityMat44() {
  var m = new glArrayType(16);
  m[0]  = 1; m[1]  = 0; m[2]  = 0; m[3]  = 0;
  m[4]  = 0; m[5]  = 1; m[6]  = 0; m[7]  = 0;
  m[8]  = 0; m[9]  = 0; m[10] = 1; m[11] = 0;
  m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1;
  return m;
};

function RotateAxis(matA, angRad, axis) {
    var aMap = [ [1, 2], [2, 0], [0, 1] ];
    var a0 = aMap[axis][0], a1 = aMap[axis][1]; 
    var sinAng = Math.sin(angRad), cosAng = Math.cos(angRad);
    var matB = new glArrayType(16);
    for ( var i = 0; i < 16; ++ i ) matB[i] = matA[i];
    for ( var i = 0; i < 3; ++ i ) {
        matB[a0*4+i] = matA[a0*4+i] * cosAng + matA[a1*4+i] * sinAng;
        matB[a1*4+i] = matA[a0*4+i] * -sinAng + matA[a1*4+i] * cosAng;
    }
    return matB;
}

function Cross( a, b ) { return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0], 0.0 ]; }
function Dot( a, b ) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }
function Normalize( v ) {
    var len = Math.sqrt( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] );
    return [ v[0] / len, v[1] / len, v[2] / len ];
}

var Camera = {};
Camera.create = function() {
    this.pos    = [0, 2, 0.0];
    this.target = [0, 0, 0];
    this.up     = [0, 0, 1];
    this.fov_y  = 90;
    this.vp     = [800, 600];
    this.near   = 0.5;
    this.far    = 100.0;
}
Camera.Perspective = function() {
    var fn = this.far + this.near;
    var f_n = this.far - this.near;
    var r = this.vp[0] / this.vp[1];
    var t = 1 / Math.tan( Math.PI * this.fov_y / 360 );
    var m = IdentityMat44();
    m[0]  = t/r; m[1]  = 0; m[2]  =  0;                              m[3]  = 0;
    m[4]  = 0;   m[5]  = t; m[6]  =  0;                              m[7]  = 0;
    m[8]  = 0;   m[9]  = 0; m[10] = -fn / f_n;                       m[11] = -1;
    m[12] = 0;   m[13] = 0; m[14] = -2 * this.far * this.near / f_n; m[15] =  0;
    return m;
}
Camera.LookAt = function() {
    var mz = Normalize( [ this.pos[0]-this.target[0], this.pos[1]-this.target[1], this.pos[2]-this.target[2] ] );
    var mx = Normalize( Cross( this.up, mz ) );
    var my = Normalize( Cross( mz, mx ) );
    var tx = Dot( mx, this.pos );
    var ty = Dot( my, this.pos );
    var tz = Dot( [-mz[0], -mz[1], -mz[2]], this.pos ); 
    var m = IdentityMat44();
    m[0]  = mx[0]; m[1]  = my[0]; m[2]  = mz[0]; m[3]  = 0;
    m[4]  = mx[1]; m[5]  = my[1]; m[6]  = mz[1]; m[7]  = 0;
    m[8]  = mx[2]; m[9]  = my[2]; m[10] = mz[2]; m[11] = 0;
    m[12] = tx;    m[13] = ty;    m[14] = tz;    m[15] = 1; 
    return m;
} 

var ShaderProgram = {};
ShaderProgram.Create = function( shaderList ) {
    var shaderObjs = [];
    for ( var i_sh = 0; i_sh < shaderList.length; ++ i_sh ) {
        var shderObj = this.CompileShader( shaderList[i_sh].source, shaderList[i_sh].stage );
        if ( shderObj == 0 )
            return 0;
        shaderObjs.push( shderObj );
    }
    var progObj = this.LinkProgram( shaderObjs )
    if ( progObj != 0 ) {
        progObj.attribIndex = {};
        var noOfAttributes = gl.getProgramParameter( progObj, gl.ACTIVE_ATTRIBUTES );
        for ( var i_n = 0; i_n < noOfAttributes; ++ i_n ) {
            var name = gl.getActiveAttrib( progObj, i_n ).name;
            progObj.attribIndex[name] = gl.getAttribLocation( progObj, name );
        }
        progObj.unifomLocation = {};
        var noOfUniforms = gl.getProgramParameter( progObj, gl.ACTIVE_UNIFORMS );
        for ( var i_n = 0; i_n < noOfUniforms; ++ i_n ) {
            var name = gl.getActiveUniform( progObj, i_n ).name;
            progObj.unifomLocation[name] = gl.getUniformLocation( progObj, name );
        }
    }
    return progObj;
}
ShaderProgram.AttributeIndex = function( progObj, name ) { return progObj.attribIndex[name]; } 
ShaderProgram.UniformLocation = function( progObj, name ) { return progObj.unifomLocation[name]; } 
ShaderProgram.Use = function( progObj ) { gl.useProgram( progObj ); } 
ShaderProgram.SetUniformI1  = function( progObj, name, val ) { if(progObj.unifomLocation[name]) gl.uniform1i( progObj.unifomLocation[name], val ); }
ShaderProgram.SetUniformF1  = function( progObj, name, val ) { if(progObj.unifomLocation[name]) gl.uniform1f( progObj.unifomLocation[name], val ); }
ShaderProgram.SetUniformF2  = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform2fv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniformF3  = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform3fv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniformF4  = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform4fv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniformM33 = function( progObj, name, mat ) { if(progObj.unifomLocation[name]) gl.uniformMatrix3fv( progObj.unifomLocation[name], false, mat ); }
ShaderProgram.SetUniformM44 = function( progObj, name, mat ) { if(progObj.unifomLocation[name]) gl.uniformMatrix4fv( progObj.unifomLocation[name], false, mat ); }
ShaderProgram.CompileShader = function( source, shaderStage ) {
    var shaderScript = document.getElementById(source);
    if (shaderScript)
      source = shaderScript.text;
    var shaderObj = gl.createShader( shaderStage );
    gl.shaderSource( shaderObj, source );
    gl.compileShader( shaderObj );
    var status = gl.getShaderParameter( shaderObj, gl.COMPILE_STATUS );
    if ( !status ) alert(gl.getShaderInfoLog(shaderObj));
    return status ? shaderObj : null;
} 
ShaderProgram.LinkProgram = function( shaderObjs ) {
    var prog = gl.createProgram();
    for ( var i_sh = 0; i_sh < shaderObjs.length; ++ i_sh )
        gl.attachShader( prog, shaderObjs[i_sh] );
    gl.linkProgram( prog );
    status = gl.getProgramParameter( prog, gl.LINK_STATUS );
    if ( !status ) alert("Could not initialise shaders");
    gl.useProgram( null );
    return status ? prog : null;
}

var VertexBuffer = {};
VertexBuffer.Create = function( attributes, indices ) {
    var buffer = {};
    buffer.buf = [];
    buffer.attr = []
    for ( var i = 0; i < attributes.length; ++ i ) {
        buffer.buf.push( gl.createBuffer() );
        buffer.attr.push( { size : attributes[i].attrSize, loc : attributes[i].attrLoc } );
        gl.bindBuffer( gl.ARRAY_BUFFER, buffer.buf[i] );
        gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( attributes[i].data ), gl.STATIC_DRAW );
    }
    buffer.inx = gl.createBuffer();
    gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, buffer.inx );
    gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( indices ), gl.STATIC_DRAW );
    buffer.inxLen = indices.length;
    gl.bindBuffer( gl.ARRAY_BUFFER, null );
    gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null );
    return buffer;
}
VertexBuffer.Draw = function( bufObj ) {
  for ( var i = 0; i < bufObj.buf.length; ++ i ) {
        gl.bindBuffer( gl.ARRAY_BUFFER, bufObj.buf[i] );
        gl.vertexAttribPointer( bufObj.attr[i].loc, bufObj.attr[i].size, gl.FLOAT, false, 0, 0 );
        gl.enableVertexAttribArray( bufObj.attr[i].loc );
    }
    gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufObj.inx );
    gl.drawElements( gl.TRIANGLES, bufObj.inxLen, gl.UNSIGNED_SHORT, 0 );
    for ( var i = 0; i < bufObj.buf.length; ++ i )
       gl.disableVertexAttribArray( bufObj.attr[i].loc );
    gl.bindBuffer( gl.ARRAY_BUFFER, null );
    gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null );
}

initScene();

})();

html,body {
    height: 100%;
    width: 100%;
    margin: 0;
    overflow: hidden;
}

#gui {
    position : absolute;
    top : 0;
    left : 0;
}

<script id="gouraud-shader-vs" type="x-shader/x-vertex">
  precision mediump float;
  
  attribute vec3 inPos;
  attribute vec3 inNV;
  attribute vec3 inCol;
  
  varying vec3 vertPos;
  varying vec3 vertNV;
  varying vec3 vertCol;
  
  uniform mat4 u_projectionMat44;
  uniform mat4 u_viewMat44;
  uniform mat4 u_modelMat44;

  struct TLightSource
  {
      vec3  lightPos;
      vec3  ambient;
      vec3  diffuse;
      vec3  specular;
      float shininess;
  };

  uniform TLightSource u_lightSource;
  
  vec3 Light( vec3 eyeV, vec3 N, vec3 P )
  {
      vec3  lightCol  = u_lightSource.ambient;
      vec3  L         = normalize( u_lightSource.lightPos-P );
      float NdotL     = max( 0.0, dot( N, L ) );
      lightCol       += NdotL * u_lightSource.diffuse;
      vec3  H         = normalize( eyeV + L );
      float NdotH     = max( 0.0, dot( N, H ) );
      float kSpecular = ( u_lightSource.shininess + 2.0 ) * pow( NdotH, u_lightSource.shininess ) / ( 2.0 * 3.14159265 );
      lightCol       += kSpecular * u_lightSource.specular;
      return lightCol; 
  }
  
  void main()
  {
      vec3 modelNV  = mat3( u_modelMat44 ) * normalize( inNV );
      vertNV        = mat3( u_viewMat44 ) * modelNV;
      vec4 modelPos = u_modelMat44 * vec4( inPos, 1.0 );
      vec4 viewPos  = u_viewMat44 * modelPos;
      vertPos       = viewPos.xyz / viewPos.w;
      vec3 eyeV     = normalize( -vertPos );
      vec3 normalV  = normalize( vertNV ) * sign(vertNV.z);
      vertCol       = inCol * Light( eyeV, normalV, vertPos );
      gl_Position   = u_projectionMat44 * viewPos;
  }
  </script>
  
  <script id="gouraud-shader-fs" type="x-shader/x-fragment">
  precision mediump float;
  
  varying vec3 vertPos;
  varying vec3 vertNV;
  varying vec3 vertCol;
  
  void main()
  {
      gl_FragColor = vec4( vertCol, 1.0 );
  }
  </script>

<script id="phong-shader-vs" type="x-shader/x-vertex">
precision mediump float;

attribute vec3 inPos;
attribute vec3 inNV;
attribute vec3 inCol;

varying vec3 vertPos;
varying vec3 vertNV;
varying vec3 vertCol;

uniform mat4 u_projectionMat44;
uniform mat4 u_viewMat44;
uniform mat4 u_modelMat44;

void main()
{
  vec3 modelNV  = mat3( u_modelMat44 ) * normalize( inNV );
  vertNV        = mat3( u_viewMat44 ) * modelNV;
  vertCol       = inCol;
  vec4 modelPos = u_modelMat44 * vec4( inPos, 1.0 );
  vec4 viewPos  = u_viewMat44 * modelPos;
  vertPos       = viewPos.xyz / viewPos.w;
  gl_Position   = u_projectionMat44 * viewPos;
}
</script>

<script id="phong-shader-fs" type="x-shader/x-fragment">
precision mediump float;

varying vec3 vertPos;
varying vec3 vertNV;
varying vec3 vertCol;

struct TLightSource
{
  vec3  lightPos;
  vec3  ambient;
  vec3  diffuse;
  vec3  specular;
  float shininess;
};

uniform TLightSource u_lightSource;

vec3 Light( vec3 eyeV, vec3 N, vec3 P )
{
  vec3  lightCol  = u_lightSource.ambient;
  vec3  L         = normalize( u_lightSource.lightPos - P );
  float NdotL     = max( 0.0, dot( N, L ) );
  lightCol       += NdotL * u_lightSource.diffuse;
  vec3  H         = normalize( eyeV + L );
  float NdotH     = max( 0.0, dot( N, H ) );
  float kSpecular = ( u_lightSource.shininess + 2.0 ) * pow( NdotH, u_lightSource.shininess ) / ( 2.0 * 3.14159265 );
  lightCol       += kSpecular * u_lightSource.specular;
  return lightCol; 
}

void main()
{
  vec3 eyeV    = normalize( -vertPos );
  vec3 normalV = normalize( vertNV ) * sign(vertNV.z);
  vec3 color   = vertCol * Light( eyeV, normalV, vertPos );
  gl_FragColor = vec4( color, 1.0 );
}
</script>

<form id="gui" name="inputs"><table><tr>
    <td><font color= #CCF>Shading:</font></td> 
    <td><select id="shading">>
        <option value="0">Gouraud</option>
        <option value="1">Phong</option>
    </select></td>
    </tr><tr>
    <td><font color= #CCF>Shininess:</font></td>
    <td><input type="range" id="shininess" min="0" max="100" value="10"/></td>
</tr></table></form>
<canvas id="canvas" style="border: none;" width="100%" height="100%"></canvas>

这篇关于纹理平面上的 OpenGL 照明不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆