在 GLSL 中使用 OpenGL Toon Shader

发布于 2024-11-03 05:22:34 字数 340 浏览 4 评论 0原文

我有兴趣学习如何用 OpenGL 着色语言编写卡通着色器。我找到了一个 演示,但无法获取演示在我的计算机上运行。我遇到的问题是编写一个使用此着色器的应用程序。有人可以告诉我如何编写一个使用此着色器的简单应用程序吗?我在 Linux 上使用 GLSL 1.2 (OpenGL 2.1)。

I'm interested in learning how to write toon shaders in OpenGL Shading Language. I found a demo, but haven't been able to get the demo running on my computer. The trouble I'm having is with writing an application which will use this shader. Could somebody please show me how to write a simple application which would use this shader? I'm using GLSL 1.2 (OpenGL 2.1) on Linux.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

迷迭香的记忆 2024-11-10 05:22:34

这是主要草图:

/*
* 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;
}

如果有帮助,此处是压缩的处理项目。安装Processing后,将文件解压缩到默认的Processing文件夹(~/Documents/Processing)并运行Processing >它应该显示在“文件”>“文件”下Sketchbook

这是一个屏幕截图:
GLSL 卡通着色器示例

HTH

更新

处理现在提供了一个很好的 PShader 课程和综合教程
它包括一个卡通着色器:

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

Here is the main sketch:

/*
* 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;
}

Here is the GLSL class used:

/*
* 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);
  }

}

And the GLSL code,
the vertex shader: 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;
}

And the fragment shader: 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;
}

If it helps, here is the zipped Processing project. Once you've installed Processing, unzip the file into the default Processing folder(~/Documents/Processing) and run Processing > it should show under File > Sketchbook

And here's a screenshot:
GLSL toon shader example

HTH

Update

Processing now provides a nice PShader class and comprehensive tutorial.
It incluses a Toon shader:

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;  
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文