/// LSU EE 4702-1 (Fall 2017), GPU Programming // /// See demo-10-shader.cc for details. // Specify version of OpenGL Shading Language. // #version 450 compatibility // The extension below defines useful--though deprecated--shader input // and output variables. The code in this file lazily makes use of // them, the code in file demo-10-shdr-geo.cc defines its own shader // input and output variables and so does not need the extension // below. The purpose of GL_EXT_geometry_shader was to provide // geometry shader functionality at a time when OpenGL lacked // it. Current versions of OpenGL support geometry shaders, and so the // extension is only needed in old code (or for those who like their // variables predefined). // #extension GL_EXT_geometry_shader : enable vec4 generic_lighting (vec4 vertex_e, vec4 color, vec3 normal_e, bool front_facing); /// Declare Uniform Variables // layout ( location = 0 ) uniform float bulge_loc; layout ( location = 1 ) uniform float bulge_dist_thresh; layout ( location = 2 ) uniform float wire_radius; /// Declare (Bind) Buffer Objects // layout ( binding = 1 ) buffer Helix_Coord { vec4 helix_coord[]; }; uniform sampler2D tex_unit_0; /// /// Shader Input and Output Variables /// // Declare variables for communication between vertex shader // and fragment shader. // #ifdef _VERTEX_SHADER_ // Helix Index: An integer giving position along helix. // Used to index the helix coordinate array. // layout ( location = 1 ) in int helix_index; out Data { vec3 normal_e; vec4 vertex_e; vec2 tex_coord; int hidx; }; #endif #ifdef _GEOMETRY_SHADER_ layout ( triangles ) in; layout ( triangle_strip, max_vertices = 4 ) out; in Data { vec3 normal_e; vec4 vertex_e; vec2 tex_coord; int hidx; } In[3]; out Data { vec3 normal_e; vec4 vertex_e; vec2 tex_coord; int hidx; }; #endif #ifdef _FRAGMENT_SHADER_ in Data { vec3 normal_e; vec4 vertex_e; vec2 tex_coord; int hidx; }; #endif /// /// Shaders /// #ifdef _VERTEX_SHADER_ void vs_main_basic() { // Perform basic vertex shading operations. // Transform vertex to clip space. gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; // Compute eye-space vertex coordinate and normal. // These are outputs of the vertex shader and inputs to the frag shader. // vertex_e = gl_ModelViewMatrix * gl_Vertex; normal_e = normalize(gl_NormalMatrix * gl_Normal); // Copy color to output unmodified. Lighting calculations will // be performed in the fragment shader. // gl_BackColor = gl_FrontColor = gl_Color; // Copy texture coordinate to output (no need to modify it). tex_coord = gl_MultiTexCoord0.xy; } void vs_main_helix() { // Perform basic vertex shading operations, but also: // - Compute wire surface coordinates. // - Adjust wire diameter based on location of bulge. // // Note that this shader only works for the helix. // Pass helix index to fragment shader output. // hidx = helix_index; // Set wire radius based on location of bulge. // float radius = wire_radius * ( hidx == int(bulge_loc) ? 1.2f : 1.0f ); /// Compute wire surface location by adding normal to helix coordinate. // vec4 vertex_o; vertex_o.xyz = helix_coord[hidx].xyz + radius * gl_Normal; vertex_o.w = 1; // Transform vertex coordinate to clip space. // gl_Position = gl_ModelViewProjectionMatrix * vertex_o; // Compute eye-space coordinates for vertex and normal. // vertex_e = gl_ModelViewMatrix * vertex_o; normal_e = normalize(gl_NormalMatrix * gl_Normal); // Pass color along to next stage in pipeline. // gl_BackColor = gl_FrontColor = gl_Color; // Pass texture coordinate to next stage in pipeline. // Only copy x and y components since it's a 2D texture. // tex_coord = gl_MultiTexCoord0.xy; } #endif #ifdef _GEOMETRY_SHADER_ void gs_main_helix() { /// Geometry Shader // // Pre-defined input: gl_PositionIn[] (array of vec4, size determined by prim) // Pre-defined output: gl_Position (vec4, read when EmitVertex called). // // Most other inputs and outputs should be declared by programmer, // but for compatibility gl_FrontColor, etc., available. // Adjust color of certain triangles. const bool type_a = In[0].hidx < In[2].hidx; vec4 color_adjust = type_a ? vec4(0.5,0.5,0.5,1) : vec4(1); for ( int i=0; i<3; i++ ) { // Send the adjusted colors. // gl_FrontColor = gl_FrontColorIn[i] * color_adjust; gl_BackColor = gl_BackColorIn[i] * color_adjust; // Pass the other values through unmodified. // gl_Position = gl_PositionIn[i]; tex_coord = In[i].tex_coord; normal_e = In[i].normal_e; vertex_e = In[i].vertex_e; EmitVertex(); } EndPrimitive(); } #endif #ifdef _FRAGMENT_SHADER_ void fs_main_phong() { // Perform lighting, fetch and blend texture, then emit fragment. // // Note that in the fixed-function pipeline lighting would be performed // in the vertex shader. // Note: gl_Color in fragment shader is either gl_FrontColor or gl_BackColor // in vertex shader. // Get filtered texel. // vec4 texel = texture(tex_unit_0,tex_coord); // Compute lighted color of fragment. // vec4 lighted_color = generic_lighting( vertex_e, gl_Color, normalize(normal_e), gl_FrontFacing ); // Multiply filtered texel color with lighted color of fragment. // gl_FragColor = texel * lighted_color; // Copy fragment depth unmodified. // gl_FragDepth = gl_FragCoord.z; } #endif vec4 generic_lighting(vec4 vertex_e, vec4 color, vec3 normal_e, bool front_facing) { // Return lighted color of vertex_e. // vec4 light_pos = gl_LightSource[0].position; vec3 v_vtx_light = light_pos.xyz - vertex_e.xyz; float dist = length(v_vtx_light); float d_n_vl = dot(normalize(normal_e), v_vtx_light) / dist; float phase_light = max(0, front_facing ? d_n_vl : -d_n_vl ); vec3 ambient_light = gl_LightSource[0].ambient.rgb; vec3 diffuse_light = gl_LightSource[0].diffuse.rgb; float distsq = dist * dist; float atten_inv = gl_LightSource[0].constantAttenuation + gl_LightSource[0].linearAttenuation * dist + gl_LightSource[0].quadraticAttenuation * distsq; vec4 lighted_color; lighted_color.rgb = color.rgb * gl_LightModel.ambient.rgb + color.rgb * ( ambient_light + phase_light * diffuse_light ) / atten_inv; lighted_color.a = color.a; return lighted_color; }