如何在 OpenGL ES 2.0 中获得“发光”着色器效果?

Posted

技术标签:

【中文标题】如何在 OpenGL ES 2.0 中获得“发光”着色器效果?【英文标题】:How to get a "Glow" shader effect in OpenGL ES 2.0? 【发布时间】:2011-12-31 06:29:26 【问题描述】:

我正在为 ios 编写一个 3D 应用程序。我是 OpenGL ES 2.0 的新手,所以我仍然在编写基本的着色器。 我真的需要根据纹理在我的一些模型上实现“发光”效果。

这是一个示例:

我正在寻找 OpenGL ES 2.0 的代码示例。我在 Internet 上找到的大多数代码都是用于桌面 OpenGL 或 D3D。

有什么想法吗?

【问题讨论】:

着色器效果在 opengl ES 2.0 和桌面 opengl 之间差别很小。如果你找到了一个很好的教程来做你想做的事,那么移植它应该是微不足道的。 感谢您的安慰,这是另一件困扰我的事情。一些(通常是旧的)示例使用输入/输出变量,我似乎在 ES 文档中找不到。我会继续挖掘,但任何好的例子通常都是我研究和理解如何使用 GLSL 的一个飞跃。 有没有人有这方面的安卓代码? O'Reilly 的书“iPhone 3D 编程”中有一个巧妙的实现:shop.oreilly.com/product/9780596804831.do @MateuszStawecki 你终于实现了发光效果了吗? 【参考方案1】:

首先,有大量的算法和技术可以生成发光效果。 我只想介绍一种可能性。

创建一个发光的材质。 为此,我使用了修改后的Blinn-Phong 光照模型,其中光源的方向始终是片段法线向量的反方向。

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

uniform float u_glow;

void main()

    vec3 color = vertCol;

    float shininess = 10.0;
    vec3  normalV = normalize( vertNV );
    vec3  eyeV    = normalize( -vertPos );
    vec3  halfV   = normalize( eyeV + normalV );
    float NdotH   = max( 0.0, dot( normalV, halfV ) );
    float glowFac = ( shininess + 2.0 ) * pow( NdotH, shininess ) / ( 2.0 * 3.14159265 );

    gl_FragColor = vec4( u_glow * (0.1 + color.rgb * glowFac * 0.5), 1.0 );

在第二步中,对输出执行高斯模糊算法。场景被写入帧缓冲区,纹理绑定到颜色平面。屏幕空间通道使用纹理作为输入来模糊输出。 出于性能原因,首先沿视口的 X 轴执行模糊算法,然后再沿视口的 Y 轴执行模糊算法。

varying vec2 vertPos;
uniform sampler2D u_textureCol;
uniform vec2 u_textureSize;
uniform float u_sigma;
uniform int u_width;

float CalcGauss( float x, float sigma ) 

  float coeff = 1.0 / (2.0 * 3.14157 * sigma);
  float expon = -(x*x) / (2.0 * sigma);
  return (coeff*exp(expon));


void main()

    vec2 texC = vertPos.st * 0.5 + 0.5;
    vec4 texCol = texture( u_textureCol, texC );
    vec4 gaussCol = vec4( texCol.rgb, 1.0 );
    vec2 step = 1.0 / u_textureSize;
    for ( int i = 1; i <= u_width; ++ i )
    
        vec2 actStep = vec2( float(i) * step.x, 0.0 );   // this is for the X-axis
        // vec2 actStep = vec2( 0.0, float(i) * step.y );   this would be for the Y-axis

        float weight = CalcGauss( float(i) / float(u_width), u_sigma );
        texCol = texture2D( u_textureCol, texC + actStep );    
        gaussCol += vec4( texCol.rgb * weight, weight );
        texCol = texture2D( u_textureCol, texC - actStep );
        gaussCol += vec4( texCol.rgb * weight, weight );
    
    gaussCol.rgb /= gaussCol.w;
    gl_FragColor = vec4( gaussCol.rgb, 1.0 );

对于模糊算法的实现,另请参阅问题的答案:

OpenGL es 2.0 Gaussian blur on triangle What kind of blurs can be implemented in pixel shaders?

请参阅以下类似的 WebGL 示例,该示例将所有内容放在一起:

var readInput = true;
function changeEventHandler(event)
    readInput = true;

  
(function loadscene() 
  
  var resize, gl, progDraw, progBlurX, progPost, vp_size, blurFB;
  var bufCube = ;
  var bufQuad = ;
  var shininess = 10.0;
  var glow = 10.0;
  var sigma = 0.8;
  
  function render(delteMS)

      //if ( readInput ) 
          readInput = false;
          var sliderScale = 100;
          shininess = document.getElementById( "shine" ).value;
          glow      = document.getElementById( "glow" ).value / sliderScale;
          sigma     = document.getElementById( "sigma" ).value / sliderScale;
      //

      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 );

      // set up framebuffer
      gl.bindFramebuffer( gl.FRAMEBUFFER, blurFB[0] );
      gl.viewport( 0, 0, blurFB[0].width, blurFB[0].height );
      gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
  
      // set up draw shader
      ShaderProgram.Use( progDraw.prog );
      ShaderProgram.SetUniformM44( progDraw.prog, "u_projectionMat44", Camera.Perspective() );
      ShaderProgram.SetUniformM44( progDraw.prog, "u_viewMat44", Camera.LookAt() );
      var modelMat = IdentityMat44()
      modelMat = RotateAxis( modelMat, CalcAng( delteMS, 13.0 ), 0 );
      modelMat = RotateAxis( modelMat, CalcAng( delteMS, 17.0 ), 1 );
      ShaderProgram.SetUniformM44( progDraw.prog, "u_modelMat44", modelMat );
      ShaderProgram.SetUniformF1( progDraw.prog, "u_shininess", shininess );
      ShaderProgram.SetUniformF1( progDraw.prog, "u_glow", glow );
      
      // draw scene
      VertexBuffer.Draw( bufCube );

      // set blur-X framebuffer and bind frambuffer texture
      gl.bindFramebuffer( gl.FRAMEBUFFER, blurFB[1] );
      gl.viewport( 0, 0, blurFB[1].width, blurFB[1].height );
      gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
      var texUnit = 1;
      gl.activeTexture( gl.TEXTURE0 + texUnit );
      gl.bindTexture( gl.TEXTURE_2D, blurFB[0].color0_texture );

      // set up blur-X shader
      ShaderProgram.Use( progBlurX.prog );
      ShaderProgram.SetUniformI1( progBlurX.prog , "u_texture", texUnit )
      ShaderProgram.SetUniformF2( progBlurX.prog , "u_textureSize", vp_size );
      ShaderProgram.SetUniformF1( progBlurX.prog , "u_sigma", sigma )

      // draw full screen space
      gl.enableVertexAttribArray( progBlurX.inPos );
      gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos );
      gl.vertexAttribPointer( progBlurX.inPos, 2, gl.FLOAT, false, 0, 0 ); 
      gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx );
      gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
      gl.disableVertexAttribArray( progBlurX.inPos );

      // reset framebuffer and bind frambuffer texture
      gl.bindFramebuffer( gl.FRAMEBUFFER, null );
      gl.viewport( 0, 0, vp_size[0], vp_size[1] );
      gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
      texUnit = 2;
      gl.activeTexture( gl.TEXTURE0 + texUnit );
      gl.bindTexture( gl.TEXTURE_2D, blurFB[1].color0_texture );

      // set up pst process shader
      ShaderProgram.Use( progPost.prog );
      ShaderProgram.SetUniformI1( progPost.prog, "u_texture", texUnit )
      ShaderProgram.SetUniformF2( progPost.prog, "u_textureSize", vp_size );
      ShaderProgram.SetUniformF1( progPost.prog, "u_sigma", sigma );

      // draw full screen space
      gl.enableVertexAttribArray( progPost.inPos );
      gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos );
      gl.vertexAttribPointer( progPost.inPos, 2, gl.FLOAT, false, 0, 0 ); 
      gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx );
      gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
      gl.disableVertexAttribArray( progPost.inPos );

      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];

      var fbsize = Math.max(vp_size[0], vp_size[1])-1;
      fbsize = 1 << 31 - Math.clz32(fbsize); // nearest power of 2
      fbsize = fbsize * 2

      blurFB = [];
      for ( var i = 0; i < 2; ++ i ) 
          fb = gl.createFramebuffer();
          fb.width = fbsize;
          fb.height = fbsize;
          gl.bindFramebuffer( gl.FRAMEBUFFER, fb );
          fb.color0_texture = gl.createTexture();
          gl.bindTexture( gl.TEXTURE_2D, fb.color0_texture );
          gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
          gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
          gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, fb.width, fb.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null );
          fb.renderbuffer = gl.createRenderbuffer();
          gl.bindRenderbuffer( gl.RENDERBUFFER, fb.renderbuffer );
          gl.renderbufferStorage( gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, fb.width, fb.height );
          gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fb.color0_texture, 0 );
          gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, fb.renderbuffer );
          gl.bindTexture( gl.TEXTURE_2D, null );
          gl.bindRenderbuffer( gl.RENDERBUFFER, null );
          gl.bindFramebuffer( gl.FRAMEBUFFER, null );
          blurFB.push( fb );
      
  
  
  function initScene() 
  
      canvas = document.getElementById( "canvas");
      gl = canvas.getContext( "experimental-webgl" );
      if ( !gl )
        return null;
  
      progDraw = 
      progDraw.prog = ShaderProgram.Create( 
        [  source : "draw-shader-vs", stage : gl.VERTEX_SHADER ,
           source : "draw-shader-fs", stage : gl.FRAGMENT_SHADER 
        ] );
      if ( !progDraw.prog )
          return null;
      progDraw.inPos = gl.getAttribLocation( progDraw.prog, "inPos" );
      progDraw.inNV  = gl.getAttribLocation( progDraw.prog, "inNV" );
      progDraw.inCol = gl.getAttribLocation( progDraw.prog, "inCol" );

      progBlurX = 
      progBlurX.prog = ShaderProgram.Create( 
        [  source : "post-shader-vs", stage : gl.VERTEX_SHADER ,
           source : "blurX-shader-fs", stage : gl.FRAGMENT_SHADER 
        ] );
      progBlurX.inPos = gl.getAttribLocation( progBlurX.prog, "inPos" );
      if ( !progBlurX.prog )
          return;    

      progPost = 
      progPost.prog = ShaderProgram.Create( 
        [  source : "post-shader-vs", stage : gl.VERTEX_SHADER ,
           source : "blurY-shader-fs", stage : gl.FRAGMENT_SHADER 
        ] );
      progPost.inPos = gl.getAttribLocation( progPost.prog, "inPos" );
      if ( !progPost.prog )
          return;
      
      // create cube
      var cubePos = [
        -1.0, -1.0,  1.0,  1.0, -1.0,  1.0,  1.0,  1.0,  1.0, -1.0,  1.0,  1.0,
        -1.0, -1.0, -1.0,  1.0, -1.0, -1.0,  1.0,  1.0, -1.0, -1.0,  1.0, -1.0 ];
      var cubeCol = [ 1.0, 0.0, 0.0, 1.0, 0.5, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 ];
      var cubeHlpInx = [ 0, 1, 2, 3, 1, 5, 6, 2, 5, 4, 7, 6, 4, 0, 3, 7, 3, 2, 6, 7, 1, 0, 4, 5 ];  
      var cubePosData = [];
      for ( var i = 0; i < cubeHlpInx.length; ++ i ) 
        cubePosData.push( cubePos[cubeHlpInx[i]*3], cubePos[cubeHlpInx[i]*3+1], cubePos[cubeHlpInx[i]*3+2] );
      
      var cubeNVData = [];
      for ( var i1 = 0; i1 < cubeHlpInx.length; i1 += 4 ) 
      var nv = [0, 0, 0];
      for ( i2 = 0; i2 < 4; ++ i2 ) 
          var i = i1 + i2;
          nv[0] += cubePosData[i*3]; nv[1] += cubePosData[i*3+1]; nv[2] += cubePosData[i*3+2];
      
      for ( i2 = 0; i2 < 4; ++ i2 )
        cubeNVData.push( nv[0], nv[1], nv[2] );
      
      var cubeColData = [];
      for ( var is = 0; is < 6; ++ is ) 
        for ( var ip = 0; ip < 4; ++ ip ) 
         cubeColData.push( cubeCol[is*3], cubeCol[is*3+1], cubeCol[is*3+2] ); 
        
      
      var cubeInxData = [];
      for ( var i = 0; i < cubeHlpInx.length; i += 4 ) 
        cubeInxData.push( i, i+1, i+2, i, i+2, i+3 );   
      
      bufCube = VertexBuffer.Create(
      [  data : cubePosData, attrSize : 3, attrLoc : progDraw.inPos ,
         data : cubeNVData,  attrSize : 3, attrLoc : progDraw.inNV ,
         data : cubeColData, attrSize : 3, attrLoc : progDraw.inCol  ],
        cubeInxData );

      bufQuad.pos = gl.createBuffer();
      gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos );
      gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( [ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0 ] ), gl.STATIC_DRAW );
      bufQuad.inx = gl.createBuffer();
      gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx );
      gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( [ 0, 1, 2, 0, 2, 3 ] ), gl.STATIC_DRAW );  
        
      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, 3, 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="draw-shader-vs" type="x-shader/x-vertex">
    precision highp 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()
       
        mat4 mv       = u_viewMat44 * u_modelMat44; 
        vertCol       = inCol;
        vertNV        = normalize(mat3(mv) * inNV);
        vec4 viewPos  = mv * vec4( inPos, 1.0 );
        vertPos       = viewPos.xyz;
        gl_Position   = u_projectionMat44 * viewPos;
    
</script>
  
<script id="draw-shader-fs" type="x-shader/x-fragment">
    precision mediump float;

    varying vec3 vertPos;
    varying vec3 vertNV;
    varying vec3 vertCol;
    
    uniform float u_shininess;
    uniform float u_glow;
    
    void main()
    
        vec3 color = vertCol;
        vec3  normalV  = normalize( vertNV );
        vec3  eyeV     = normalize( -vertPos );
        vec3  halfV    = normalize( eyeV + normalV );
        float NdotH    = max( 0.0, dot( normalV, halfV ) );
        float shineFac = ( u_shininess + 2.0 ) * pow( NdotH, u_shininess ) / ( 2.0 * 3.14159265 );
        gl_FragColor   = vec4( u_glow*0.1 + color.rgb * u_glow * shineFac * 0.5, 1.0 );
     
</script>
  
<script id="post-shader-vs" type="x-shader/x-vertex">
    precision mediump float;
    
    attribute vec2 inPos;
    
    varying   vec2 pos;
    
    void main()
    
        pos = inPos;
        gl_Position = vec4( inPos, 0.0, 1.0 );
    
</script>
    
<script id="blurX-shader-fs" type="x-shader/x-fragment">
    precision mediump float;
    
    varying vec2 pos;
    
    uniform sampler2D u_texture;
    uniform vec2      u_textureSize;
    uniform float     u_sigma;
    
    float CalcGauss( float x, float sigma )
    
      float coeff = 1.0 / (2.0 * 3.14157 * sigma);
      float expon = -(x*x) / (2.0 * sigma);
      return (coeff*exp(expon));
    
    
    void main()
    
        vec2 texC = pos.st * 0.5 + 0.5;
        vec4 texCol = texture2D( u_texture, texC );
        vec4 gaussCol = vec4( texCol.rgb, 1.0 );
        float stepX = 1.0 / u_textureSize.x;
        for ( int i = 1; i <= 20; ++ i )
        
            float weight = CalcGauss( float(i) / 32.0, u_sigma * 0.5 );
            texCol = texture2D( u_texture, texC + vec2( float(i) * stepX, 0.0 ) );
            gaussCol += vec4( texCol.rgb * weight, weight );
            texCol = texture2D( u_texture, texC - vec2( float(i) * stepX, 0.0 ) );
            gaussCol += vec4( texCol.rgb * weight, weight );
        
        gaussCol.rgb /= gaussCol.w;
        gl_FragColor = vec4( gaussCol.rgb, 1.0 );
    
</script>
    
<script id="blurY-shader-fs" type="x-shader/x-fragment">
    precision mediump float;
    
    varying vec2 pos;
    
    uniform sampler2D u_texture;
    uniform vec2      u_textureSize;
    uniform float     u_sigma;
    
    float CalcGauss( float x, float sigma )
    
      float coeff = 1.0 / (2.0 * 3.14157 * sigma);
      float expon = -(x*x) / (2.0 * sigma);
      return (coeff*exp(expon));
    
    
    void main()
    
        vec2 texC = pos.st * 0.5 + 0.5;
        vec4 texCol = texture2D( u_texture, texC );
        vec4 gaussCol = vec4( texCol.rgb, 1.0 );
        float stepY = 1.0 / u_textureSize.y;
        for ( int i = 1; i <= 20; ++ i )
        
            float weight = CalcGauss( float(i) / 32.0, u_sigma * 0.5 );
            texCol = texture2D( u_texture, texC + vec2( 0.0, float(i) * stepY ) );
            gaussCol += vec4( texCol.rgb * weight, weight );
            texCol = texture2D( u_texture, texC - vec2( 0.0, float(i) * stepY ) );
            gaussCol += vec4( texCol.rgb * weight, weight );
        
        vec3 hdrCol = 2.0 * gaussCol.xyz / gaussCol.w;
        vec3 mappedCol = vec3( 1.0 ) - exp( -hdrCol.rgb * 3.0 );
        gl_FragColor = vec4( clamp( mappedCol.rgb, 0.0, 1.0 ), 1.0 );
    
</script>

<div>
    <form id="gui" name="inputs">
        <table>
            <tr> <td> <font color= #CCF>shininess</font> </td> 
                 <td> <input type="range" id="shine" min="0" max="50" value="10" onchange="changeEventHandler(event);"/></td> </tr>
            <tr> <td> <font color= #CCF>glow</font> </td> 
                 <td> <input type="range" id="glow" min="100" max="400" value="250" onchange="changeEventHandler(event);"/></td> </tr>
            <tr> <td> <font color= #CCF>blur</font> </td> 
                 <td> <input type="range" id="sigma" min="1" max="100" value="60" onchange="changeEventHandler(event);"/></td> </tr>
        </table>
    </form>
</div>

<canvas id="canvas" style="border: none;"  ></canvas>

【讨论】:

感谢您的出色回答,但为什么这行 'vertPos = pos.xyz / pos.w;'在顶点着色器中?这里有必要除以w吗?我认为在这个阶段 w 总是 1。 @wdanxna 不,在这种情况下没有必要。 @Rabbid76 代码中的第一个着色器,是片段着色器的代码。 @Summit 有一个错字fragColor 必须是gl_FragColor。答案底部示例中的代码是正确的。【参考方案2】:

GLSL Sandbox 网站有一系列着色器示例。 This one has the glow and appears to be able to compile for ES.

您应该能够修改这些以从纹理中提取 uv。

这里是some code directly from this site:

#ifdef GL_ES
precision mediump float;
#endif

#extension GL_OES_standard_derivatives : enable

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

void main(void)

    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);
    vec3 color1 = vec3(0.0, 0.3, 0.5);
    vec3 color2 = vec3(0.5, 0.0, 0.3);

    float f = 0.0;
    float g = 0.0;
    float h = 0.0;
    float PI = 3.14159265;
    for(float i = 0.0; i < 40.0; i++)
        if (floor(mouse.x * 41.0) < i)
            break;
        float s = sin(time + i * PI / 20.0) * 0.8;
        float c = cos(time + i * PI / 20.0) * 0.8;
        float d = abs(p.x + c);
        float e = abs(p.y + s);
        f += 0.001 / d;
        g += 0.001 / e;
        h += 0.00003 / (d * e);
    


    gl_FragColor = vec4(f * color1 + g * color2 + vec3(h), 1.0);

【讨论】:

以上是关于如何在 OpenGL ES 2.0 中获得“发光”着色器效果?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Android上将OpenGL ES 1.0代码转换为OpenGL Es 2.0?

如何在Android上使用OpenGL ES 2.0绘制点

OPENGL ES 2.0 知识串讲 (10) ——OPENGL ES 详解IV(纹理优化)

OPENGL ES 2.0 知识串讲 (10) ——OPENGL ES 详解IV(纹理优化)

如何在 OpenGL ES 2.0 中使用 png 图像纹理立方体?

如何在 OpenGL ES 2.0 中使用 GL_FLOAT 创建纹理?