在GLSL中使用OpenGL Toon Shader

时间:2011-04-26 20:06:50

标签: opengl glsl shader processing

我有兴趣学习如何在OpenGL着色语言中编写toon shaders。我找到了demo,但无法在我的计算机上运行演示。我遇到的麻烦是编写一个将使用此着色器的应用程序。有人可以告诉我如何编写一个简单的应用程序哪个会使用这个着色器?我在Linux上使用GLSL 1.2(OpenGL 2.1)。

1 个答案:

答案 0 :(得分:12)

这是主要草图:

/*
* Use keys 1 - 8 to play with different GLUT Solids
* mouse affects light position
* Toon Shader by Philip Rideout:
* http://www.lighthouse3d.com/opengl/glsl/index.php?toon2
*/
import processing.opengl.*;
import javax.media.opengl.*;
import javax.media.opengl.glu.*;
import com.sun.opengl.util.*; 

PGraphicsOpenGL pgl;
GL gl;
GLSL toon;
GLU glu;
GLUT glut;
boolean glInit;
int glutSolidIndex = 7;

void setup()
{
  size(600, 500, OPENGL);

  glu = new GLU();
  glut = new GLUT();

  pgl = (PGraphicsOpenGL) g;
  gl = pgl.gl;
}

void draw()
{
  background(0);
  PGraphicsOpenGL pgl = (PGraphicsOpenGL) g;
  GL gl = pgl.beginGL();

  if(!glInit){
    toon=new GLSL();
    toon.loadVertexShader("toon.vs");
    toon.loadFragmentShader("toon.fs");
    toon.useShaders();

    glInit = true;
  }

  gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT);

 //TRS
  gl.glTranslatef(width * .5, height * .5,0.0f);
  gl.glRotatef(160,1,0,0);
  gl.glRotatef(frameCount * .5,0,1,0);
  gl.glRotatef(frameCount * .5,0,0,1);
  gl.glScalef(80,80,80);
  // draw 
  toon.startShader();
  toon.uniform3f(toon.getUniformLocation("LightPosition"), mouseX-width*.5, -(mouseY-height*.5), 20.0f);
    gl.glColor3f(1.0f, 0.5f, 0.0f);
    glutSolid();
  toon.endShader();

  pgl.endGL();
}

void glutSolid(){
 switch(glutSolidIndex){
   case 0:
     glut.glutSolidCube(1);
   break;
   case 1:
     glut.glutSolidTetrahedron();
   break;
   case 2:
     glut.glutSolidOctahedron();
   break;
   case 3:
     glut.glutSolidDodecahedron();
   break;
   case 4:
     glut.glutSolidIcosahedron();
   break;
   case 5:
     glut.glutSolidSphere(1,16,8);
   break;
   case 6:
     glut.glutSolidTorus(.5,1,32,24);
   break;
   case 7:
     glut.glutSolidTeapot(1);
   break;
 }
}
void keyPressed(){
  if((int)key >= 49 && (int)key <= 56) glutSolidIndex = (int)(key) - 49;
}

这是使用的GLSL类:

/*
* Class posted by JohnG on the Processing forums:
* http://processing.org/discourse/yabb2/YaBB.pl?board=OpenGL;action=display;num=1159494801
* check it out for more details
*/
import processing.opengl.*;
import javax.media.opengl.*;
import java.nio.IntBuffer;
import java.nio.ByteBuffer;
import com.sun.opengl.util.BufferUtil;

class GLSL
{
  int programObject;
  GL gl;
  boolean vertexShaderEnabled;
  boolean vertexShaderSupported; 
  int vs;
  int fs;

  GLSL()
  {
    PGraphicsOpenGL pgl = (PGraphicsOpenGL) g;
    gl = pgl.gl;
    //gl=((PGraphicsGL)g).gl;
    String extensions = gl.glGetString(GL.GL_EXTENSIONS);
    vertexShaderSupported = extensions.indexOf("GL_ARB_vertex_shader") != -1;
    vertexShaderEnabled = true;    
    programObject = gl.glCreateProgramObjectARB(); 
    vs=-1;
    fs=-1;
  }

  void loadVertexShader(String file)
  {
    String shaderSource=join(loadStrings(file),"\n");
    vs = gl.glCreateShaderObjectARB(GL.GL_VERTEX_SHADER_ARB);
    gl.glShaderSourceARB(vs, 1, new String[]{
      shaderSource    }
    ,(int[]) null, 0);
    gl.glCompileShaderARB(vs);
    checkLogInfo(gl, vs);
    gl.glAttachObjectARB(programObject, vs); 
  }

  void loadFragmentShader(String file)
  {
    String shaderSource=join(loadStrings(file),"\n");
    fs = gl.glCreateShaderObjectARB(GL.GL_FRAGMENT_SHADER_ARB);
    gl.glShaderSourceARB(fs, 1, new String[]{
      shaderSource    }
    ,(int[]) null, 0);
    gl.glCompileShaderARB(fs);
    checkLogInfo(gl, fs);
    gl.glAttachObjectARB(programObject, fs); 
  }

  int getAttribLocation(String name)
  {
    return(gl.glGetAttribLocationARB(programObject,name));
  }

  int getUniformLocation(String name)
  {
    return(gl.glGetUniformLocationARB(programObject,name));
  }

  void useShaders()
  {
    gl.glLinkProgramARB(programObject);
    gl.glValidateProgramARB(programObject);
    checkLogInfo(gl, programObject);
  }

  void startShader()
  {
    gl.glUseProgramObjectARB(programObject); 
  }

  void endShader()
  {
    gl.glUseProgramObjectARB(0); 
  }

  void checkLogInfo(GL gl, int obj)  
  {
    IntBuffer iVal = BufferUtil.newIntBuffer(1);
    gl.glGetObjectParameterivARB(obj, GL.GL_OBJECT_INFO_LOG_LENGTH_ARB, iVal);

    int length = iVal.get();
    if (length <= 1)  
    {
      return;
    }
    ByteBuffer infoLog = BufferUtil.newByteBuffer(length);
    iVal.flip();
    gl.glGetInfoLogARB(obj, length, iVal, infoLog);
    byte[] infoBytes = new byte[length];
    infoLog.get(infoBytes);
    println("GLSL Validation >> " + new String(infoBytes));
  }

  void uniform3f(int location, float v0, float v1, float v2)
  {
    gl.glUniform3fARB(location, v0, v1, v2);
  }

  void uniform1i(int location, int v0)
  {
    gl.glUniform1iARB(location, v0);
  }

}

和GLSL代码, 顶点着色器:toon.vs

//
// Vertex shader for cartoon-style shading
//
// Author: Philip Rideout
//
// Copyright (c) 2005-2006 3Dlabs Inc. Ltd.
//
// See 3Dlabs-License.txt for license information
//

varying vec3 Normal;

void main(void)
{
    Normal = normalize(gl_NormalMatrix * gl_Normal);
    #ifdef __GLSL_CG_DATA_TYPES // Fix clipping for Nvidia and ATI
    gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
    #endif
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

片段着色器:toon.fs

/* http://www.lighthouse3d.com/opengl/glsl/index.php?toon2 */

varying vec3 Normal;

uniform vec3 LightPosition;// = vec3(10.0, 10.0, 20.0);

void main()
{
    vec4 color1 = gl_FrontMaterial.diffuse;
    vec4 color2;

    float intensity = dot(normalize(LightPosition),Normal);

    if (intensity > 0.95)      color2 = vec4(1.0, 1.0, 1.0, 1.0);
    else if (intensity > 0.75) color2 = vec4(0.8, 0.8, 0.8, 1.0);
    else if (intensity > 0.50) color2 = vec4(0.6, 0.6, 0.6, 1.0);
    else if (intensity > 0.25) color2 = vec4(0.4, 0.4, 0.4, 1.0);
    else                       color2 = vec4(0.2, 0.2, 0.2, 1.0);

    gl_FragColor = color1 * color2;
}

如果有帮助,here是压缩的Processing项目。安装Processing后,将文件解压缩到默认的Processing文件夹(〜/ Documents / Processing)并运行Processing&gt;它应该显示在File&gt;下写生

这是一个截图: GLSL toon shader example

HTH

<强>更新

现在处理提供了一个不错的PShader class and comprehensive tutorial。 它包括一个Toon着色器:

PShader toon;

void setup() {
  size(640, 360, P3D);
  noStroke();
  fill(204);
  toon = loadShader("ToonFrag.glsl", "ToonVert.glsl");
  toon.set("fraction", 1.0);
}

void draw() {
  shader(toon);
  background(0); 
  float dirY = (mouseY / float(height) - 0.5) * 2;
  float dirX = (mouseX / float(width) - 0.5) * 2;
  directionalLight(204, 204, 204, -dirX, -dirY, -1);
  translate(width/2, height/2);
  sphere(120);
}

ToonVert.glsl:

uniform mat4 transform;
uniform mat3 normalMatrix;
uniform vec3 lightNormal;

attribute vec4 vertex;
attribute vec4 color;
attribute vec3 normal;

varying vec4 vertColor;
varying vec3 vertNormal;
varying vec3 vertLightDir;

void main() {
  gl_Position = transform * vertex;  
  vertColor = color;
  vertNormal = normalize(normalMatrix * normal);
  vertLightDir = -lightNormal;
}

ToonFrag.glsl:

#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif

#define PROCESSING_LIGHT_SHADER

uniform float fraction;

varying vec4 vertColor;
varying vec3 vertNormal;
varying vec3 vertLightDir;

void main() {  
  float intensity;
  vec4 color;
  intensity = max(0.0, dot(vertLightDir, vertNormal));

  if (intensity > pow(0.95, fraction)) {
    color = vec4(vec3(1.0), 1.0);
  } else if (intensity > pow(0.5, fraction)) {
    color = vec4(vec3(0.6), 1.0);
  } else if (intensity > pow(0.25, fraction)) {
    color = vec4(vec3(0.4), 1.0);
  } else {
    color = vec4(vec3(0.2), 1.0);
  }

  gl_FragColor = color * vertColor;  
}