/*************************************************************************** *cr *cr (C) Copyright 1995-2004 The Board of Trustees of the *cr University of Illinois *cr All Rights Reserved *cr ***************************************************************************/ /*************************************************************************** * RCS INFORMATION: * * $RCSfile: vmd.frag,v $ * $Author: johns $ $Locker: $ $State: Exp $ * $Revision: 1.30 $ $Date: 2004/12/04 00:46:06 $ * *************************************************************************** * DESCRIPTION: * This file contains the VMD OpenGL fragment shader implementing * per-pixel lighting with phong highlights etc. ***************************************************************************/ // Video card defines // XXX these ought to be generated by VMD programmatically by matching // the results from glGetString(GL_RENDERER) with known renderer strings. // Perhaps the #define would be named something like: // "CARD_openglrendererstringwithspacesremoved" // For now this is hard-coded while testing on a particular video board. #if 1 #define CARD_ATIRADEON 1 #elif 1 #define CARD_NVIDIAGEFORCE 1 #else #define CARD_3DLABSWILDCAT 1 #endif // defines to workaround implementation bugs and limitations #ifdef CARD_ATIRADEON #define ALL_LIGHTS 1 #define FOG_ENABLE 1 #define TWO_SIDED_LIGHTING 1 #define TEXTURE 1 #endif #ifdef CARD_NVIDIAGEFORCE #define ALL_LIGHTS 1 #define FOG_ENABLE 1 #define TWO_SIDED_LIGHTING 1 #define TEXTURE 1 #endif #ifdef CARD_3DLABSWILDCAT #define CLAMP_WORKAROUND 1 #define POW_WORKAROUND 1 #endif // // Fragment shader varying and uniform variable definitions for data // supplied by VMD and/or the vertex shader // varying vec3 oglnormal; // interpolated normal from the vertex shader varying vec3 oglcolor; // interpolated color from the vertex shader varying vec3 V; // view direction vector uniform vec3 vmdlight0; // VMD directional lights uniform vec3 vmdlight1; uniform vec3 vmdlight2; uniform vec3 vmdlight3; uniform vec4 vmdlightscale; // VMD light on/off state for all 4 VMD lights, // represented as a scaling constant. Could be // done with on/off flags but ATI doesn't deal // well with branching constructs, so this value // is simply multiplied by the light's // contribution. Hacky, but it works for now. uniform vec4 vmdmaterial; // VMD material properties // [0] is ambient (white ambient light only) // [1] is diffuse // [2] is specular // [3] is shininess uniform float vmdopacity; // VMD global alpha value uniform int vmdfogmode; // VMD depth cueing / fog mode uniform int vmdtexturemode; // VMD texture mode 0=off 1=modulate 2=replace uniform sampler3D vmdtex0; // active 3-D texture map // // VMD Fragment Shader // void main(void) { varying vec3 objcolor; float ambient = vmdmaterial[0]; // ambient float diffuse = 0.0; float specular = 0.0; #ifdef POW_WORKAROUND // XXX 3DLabs' Wildcat VP doesn't allow pow() with variable exponents yet const float shininess = 10.0; // XXX hard-coded shininess hack #else float shininess = vmdmaterial[3]; // shininess #endif #ifdef TEXTURE // perform texturing operations for volumetric data if (vmdtexturemode == 0) { // texturing is disabled objcolor = oglcolor; } else if (vmdtexturemode == 1) { // emulate GL_MODULATE objcolor = oglcolor * vec3(texture3D(vmdtex0, gl_TexCoord[0].xyz)); } else if (vmdtexturemode == 2) { // emulate GL_REPLACE objcolor = vec3(texture3D(vmdtex0, gl_TexCoord[0].xyz)); } #else // texturing is disabled objcolor = oglcolor; #endif #if defined(TWO_SIDED_LIGHTING) #if 0 // flip the surface normal if the fragment is facing away from the viewer // as determined by polygon winding order // XXX the ATI driver can't handle this yet vec3 N = normalize(oglnormal); if (!gl_FrontFacing) { N = -N; } #else // flip the surface normal if it is facing away from the viewer // this works in most cases but can still give incorrect shading // for poorly tesellated objects. To correct this weakness, the // normal flipping will have to be done with respect to each light as well. vec3 N = normalize(faceforward(oglnormal, V, oglnormal)); #endif #else vec3 N = normalize(oglnormal); #endif // calculate diffuse lighting contribution diffuse += max(0.0, dot(N, vmdlight0)) * vmdlightscale[0]; diffuse += max(0.0, dot(N, vmdlight1)) * vmdlightscale[1]; #ifdef ALL_LIGHTS diffuse += max(0.0, dot(N, vmdlight2)) * vmdlightscale[2]; diffuse += max(0.0, dot(N, vmdlight3)) * vmdlightscale[3]; #endif diffuse *= vmdmaterial[1]; // diffuse scaling factor // calculate specular lighting contribution specular += pow(max(0.0, dot(reflect(vmdlight0, N), V)), shininess) * vmdlightscale[0]; specular += pow(max(0.0, dot(reflect(vmdlight1, N), V)), shininess) * vmdlightscale[1]; #ifdef ALL_LIGHTS specular += pow(max(0.0, dot(reflect(vmdlight2, N), V)), shininess) * vmdlightscale[2]; specular += pow(max(0.0, dot(reflect(vmdlight3, N), V)), shininess) * vmdlightscale[3]; #endif specular *= vmdmaterial[2]; // specular scaling factor vec3 color = objcolor * vec3(diffuse) + vec3(ambient + specular); // XXX the fog code appears to work except that the current ATI // and 3DLabs drivers run out of resources when it is enabled. // The ATI driver claims to run out of constants when it encounters // 'if' statements and punts to software. #ifdef FOG_ENABLE const float Log2E = 1.442695; // = log2(2.718281828) float fog = 1.0; float EyeZ = gl_FragCoord.z / gl_FragCoord.w; if (vmdfogmode == 1) { // linear fog fog = (gl_Fog.end - EyeZ) * gl_Fog.scale; } else if (vmdfogmode == 2) { // exponential fog fog = exp2(-gl_Fog.density * EyeZ * Log2E); } else if (vmdfogmode == 3) { // exponential-squared fog fog = exp2(-gl_Fog.density * gl_Fog.density * EyeZ * EyeZ * Log2E); } fog = clamp(fog, 0.0, 1.0); color = mix(vec3(gl_Fog.color), color, fog); #endif #ifdef CLAMP_WORKAROUND // OpenGL is supposed to clamping the pixel value for us, but the 3DLabs // Wildcat VP driver doesn't seem to be doing this currently, so // this extra step is hopefully a temporary workaround. color = clamp(color, 0.0, 1.0); #endif gl_FragColor = vec4(color, vmdopacity); }