0

I'm using the following shader sources for vertex and fragment.

Vertex shader source:

#define highp
attribute highp vec3 position;
uniform highp mat4 mvp;
void main(void)
{
    gl_Position = mvp * vec4(position, 1.0);
}

Fragment shader source:

#define highp
uniform highp vec3 color;
void main(void)
{
    gl_FragColor = vec4(color, 1.0);
}

However, the shader is not working. As shown in the following screen-shot, a 3D object is just colored like a 2D object:

3D object is colored like a 2D object


glGetShaderiv with GL_COMPILE_STATUS returns success == TRUE, so there is no shader compile error.

glGetShaderiv(shaderObj, GL_COMPILE_STATUS, &success);

I didn't try glGetError() in the code. I'm going to try it. But I suspect I'm not receiving any OpenGL errors.


I believe I need to adjust the color in vertex and fragment shader. How should I adjust the color in shader sources? Can anyone help me by giving a hint. So far, I couldn't resolve the issue by modifying the sources.


UPDATE

With the help of @Rabbid76 now the 3D object looks good:

3D object looks good now :)

I'm using @Rabbid76 code with a small modification: adding the #version 130 to the top of both vertex and fragment shader sources. Looks like my Intel graphics card requires the #version 130 directive, otherwise it throws some warnings and errors:

warning: extension "GL_OES_standard_derivative" unsupported in fragment shader

The #version 130 directive resolves the above warning and its subsequent errors.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Megidd
  • 7,089
  • 6
  • 65
  • 142
  • 1
    Do you get any errors when compiling the shader? Does `glGetError()` return any issues? How are you setting `color` in the fragment shader? What are you expecting to see that you aren't seeing? – user1118321 Jun 19 '18 at 05:57
  • @user1118321 I added the compile status output. – Megidd Jun 19 '18 at 06:33
  • @Rabbid76 I modified the post trying to clarify. – Megidd Jun 19 '18 at 06:34
  • 1
    @user3405291 You have to apply a light model. See [this](https://stackoverflow.com/questions/50875639/opengl-blinn-phong-model-implemented-in-shaders-give-wrong-result/50876761#50876761) or [this](https://stackoverflow.com/questions/8421778/glsl-fixed-function-fragment-program-replacement/45716107#45716107) – Rabbid76 Jun 19 '18 at 06:40
  • @Rabbid76 I'm going to study the links you provided. Thanks. – Megidd Jun 19 '18 at 06:54
  • 1
    @user3405291 See also [How does this faking the light work on aerotwist?](https://stackoverflow.com/questions/7061745/how-does-this-faking-the-light-work-on-aerotwist/45121641#45121641) – Rabbid76 Jun 19 '18 at 06:59
  • @Rabbid76 Great. I'm just learning. – Megidd Jun 19 '18 at 07:05
  • @Rabbid76 I'm studying on **lighting**, but it looks like to be a huge topic. I wonder if you can guide me to the simplest lighting code which would work in my case. Thanks. – Megidd Jun 19 '18 at 12:28

2 Answers2

5

Your shader is working correctly. It looks like it's 2D because you don't have any lighting in your shader. An object that is a uniform color will look 2D because there are no depth cues such as self shadowing, or specular highlights, etc.

user1118321
  • 25,567
  • 4
  • 55
  • 86
  • Thanks, I'm going to try lighting. – Megidd Jun 19 '18 at 06:53
  • You can start with directional lights, as they are simple to implement and create something that looks like self-shadowing even though it's not really. After that point lights are pretty easy to implement, and spot lights are just a variation on point lights. Good luck! – user1118321 Jun 19 '18 at 16:18
3

According to the comment:

I'm studying on lighting, but it looks like to be a huge topic. I wonder if you can guide me to the simplest lighting code which would work in my case

A simple lambertian diffuse "fake" light, directed from the point of view. The surface normal vector can be calculated approximately by the partial derivative of the view space position in the fragment shader. The partial derivative can be get by the functions dFdx and dFdy. For this is required OpenGL 2.0, OpenGL ES 3.0 or the OES_standard_derivatives extension:

Vertex shader

#define highp

attribute highp vec3 position;

varying vec4 v_clip_pos;

uniform highp mat4 mvp;

void main(void)
{
    v_clip_pos  = mvp * vec4(position, 1.0);
    gl_Position = v_clip_pos;
}

Fragment shader

#extension GL_OES_standard_derivatives : enable

varying vec4 v_clip_pos;

uniform highp vec3 color;

void main()
{
    vec3  ndc_pos = v_clip_pos.xyz / v_clip_pos.w;
    vec3  dx      = dFdx( ndc_pos );
    vec3  dy      = dFdy( ndc_pos );

    vec3 N = normalize(cross(dx, dy));
    N *= sign(N.z);
    vec3 L = vec3(0.0, 0.0, 1.0); 
    float NdotL = dot(N, L); 

    vec3 diffuse_color = color * NdotL;
    gl_FragColor       = vec4( diffuse_color.rgb, 1.0 );
} 

See the WebGL example which demonstrates the shader:

var readInput = true;
  function changeEventHandler(event){
    readInput = true;
  }
  
  (function loadscene() {
  
  var gl, progDraw, vp_size;
  var bufCube = {};
  
  function render(delteMS){

      Camera.create();
      Camera.vp = vp_size;
          
      gl.viewport( 0, 0, vp_size[0], vp_size[1] );
      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 draw shader
      ShaderProgram.Use( progDraw );
      ShaderProgram.SetUniformM44( progDraw, "u_projectionMat44", Camera.Perspective() );
      ShaderProgram.SetUniformM44( progDraw, "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, "u_modelMat44", modelMat );
      ShaderProgram.SetUniformF3( progDraw, "color", [0.9, 0.9, 0.5] );
      
      // draw scene
      VertexBuffer.Draw( bufCube );

      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];
  }
  
  function initScene() {
  
      canvas = document.getElementById( "canvas");
      gl = canvas.getContext( "experimental-webgl" );
      if ( !gl )
        return null;
      var ext_standard_derivatives = gl.getExtension( "OES_standard_derivatives" );  // dFdx, dFdy
      if (!ext_standard_derivatives)
          alert('no standard derivatives support (no dFdx, dFdy)');
      
      progDraw = ShaderProgram.Create( 
        [ { source : "draw-shader-vs", stage : gl.VERTEX_SHADER },
          { source : "draw-shader-fs", stage : gl.FRAGMENT_SHADER }
        ] );
      if ( !progDraw.progObj )
          return null;
      progDraw.inPos = ShaderProgram.AttributeIndex( progDraw, "inPos" );
      progDraw.inNV  = ShaderProgram.AttributeIndex( progDraw, "inNV" );
     // create sphere
      var layer_size = 16, circum_size = 32;
      var rad_circum = 1.0;
      var rad_tube = 0.5;
      var sphere_pts = [];
      var sphere_nv = [];
      sphere_pts.push( 0.0, 0.0, -rad_circum );
      sphere_nv.push( 0.0, 0.0, -1.0 );
      for ( var i_l = 1; i_l < layer_size; ++ i_l ) {
          var angH = (1.0 - i_l / layer_size) * Math.PI;
          var h = Math.cos( angH );
          var r = Math.sin( angH );
          for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
              var circumX = Math.cos(2 * Math.PI * i_c / circum_size);
              var circumY = Math.sin(2 * Math.PI * i_c / circum_size);
              sphere_pts.push( r * circumX * rad_circum, r * circumY * rad_circum, h * rad_circum );
              sphere_nv.push( r * circumX, r * circumY, h );
          }
      }
      sphere_pts.push( 0.0, 0.0, rad_circum );
      sphere_nv.push( 0.0, 0.0, 1.0 );
      var sphere_inx = [];
      for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
          sphere_inx.push( i_c+1, 0, (i_c+1) % circum_size + 1 )
      }
      for ( var i_l = 0; i_l < layer_size-2; ++ i_l ) {
          var l1 = i_l * circum_size + 1;
          var l2 = (i_l+1) * circum_size + 1
          for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
              var i_n = (i_c+1) % circum_size;
              sphere_inx.push( l1+i_c, l1+i_n, l2+i_c, l1+i_n, l2+i_n, l2+i_c );
          }
      }
      for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
          var i_start = 1 + (layer_size-2) * circum_size;
          var i_n = (i_c+1) % circum_size;
          sphere_inx.push( i_start + i_c, i_start + i_n, sphere_pts.length/3-1 );
      }
      bufCube = VertexBuffer.Create(
      [ { data : sphere_pts, attrSize : 3, attrLoc : progDraw.inPos },
        { data : sphere_nv,  attrSize : 3, attrLoc : progDraw.inNV } ],
        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, 1.5, 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 prog = {}
      prog.progObj = this.LinkProgram( shaderObjs )
      if ( prog.progObj ) {
          prog.attribIndex = {};
          var noOfAttributes = gl.getProgramParameter( prog.progObj, gl.ACTIVE_ATTRIBUTES );
          for ( var i_n = 0; i_n < noOfAttributes; ++ i_n ) {
              var name = gl.getActiveAttrib( prog.progObj, i_n ).name;
              prog.attribIndex[name] = gl.getAttribLocation( prog.progObj, name );
          }
          prog.unifomLocation = {};
          var noOfUniforms = gl.getProgramParameter( prog.progObj, gl.ACTIVE_UNIFORMS );
          for ( var i_n = 0; i_n < noOfUniforms; ++ i_n ) {
              var name = gl.getActiveUniform( prog.progObj, i_n ).name;
              prog.unifomLocation[name] = gl.getUniformLocation( prog.progObj, name );
          }
      }
      return prog;
  }
  ShaderProgram.AttributeIndex = function( prog, name ) { return prog.attribIndex[name]; } 
  ShaderProgram.UniformLocation = function( prog, name ) { return prog.unifomLocation[name]; } 
  ShaderProgram.Use = function( prog ) { gl.useProgram( prog.progObj ); } 
  ShaderProgram.SetUniformI1  = function( prog, name, val ) { if(prog.unifomLocation[name]) gl.uniform1i( prog.unifomLocation[name], val ); }
  ShaderProgram.SetUniformF1  = function( prog, name, val ) { if(prog.unifomLocation[name]) gl.uniform1f( prog.unifomLocation[name], val ); }
  ShaderProgram.SetUniformF2  = function( prog, name, arr ) { if(prog.unifomLocation[name]) gl.uniform2fv( prog.unifomLocation[name], arr ); }
  ShaderProgram.SetUniformF3  = function( prog, name, arr ) { if(prog.unifomLocation[name]) gl.uniform3fv( prog.unifomLocation[name], arr ); }
  ShaderProgram.SetUniformF4  = function( prog, name, arr ) { if(prog.unifomLocation[name]) gl.uniform4fv( prog.unifomLocation[name], arr ); }
  ShaderProgram.SetUniformM33 = function( prog, name, mat ) { if(prog.unifomLocation[name]) gl.uniformMatrix3fv( prog.unifomLocation[name], false, mat ); }
  ShaderProgram.SetUniformM44 = function( prog, name, mat ) { if(prog.unifomLocation[name]) gl.uniformMatrix4fv( prog.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();
  
  })();
<script id="draw-shader-vs" type="x-shader/x-vertex">
precision highp float;

attribute vec3 inPos;
attribute vec3 inNV;

varying vec4 v_clip_pos;

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

void main()
{   
    vec4 pos  = u_viewMat44 * u_modelMat44 * vec4( inPos, 1.0 );

    v_clip_pos  = u_projectionMat44 * pos;
    gl_Position = v_clip_pos;
}
</script>
  
<script id="draw-shader-fs" type="x-shader/x-fragment">
#extension GL_OES_standard_derivatives : enable
precision mediump float;

varying vec4 v_clip_pos;

uniform highp vec3 color;

void main()
{
    vec3  ndc_pos = v_clip_pos.xyz / v_clip_pos.w;
    vec3  dx      = dFdx( ndc_pos );
    vec3  dy      = dFdy( ndc_pos );

    vec3 N = normalize(cross(dx, dy));
    N *= sign(N.z);
    vec3 L = vec3(0.0, 0.0, 1.0); 
    float NdotL = dot(N, L); 

    vec3 diffuse_color = color * NdotL;
    gl_FragColor       = vec4( diffuse_color.rgb, 1.0 );
} 
</script>

<canvas id="canvas" style="border: none;" width="100%" height="100%"></canvas>
Rabbid76
  • 202,892
  • 27
  • 131
  • 174