原理:计算出法线,将顶点沿着法线方向移动自定义距离,其他不变。
// Normal visualizer
// Fragment Shader
// Graham Sellers
// OpenGL SuperBible
#version 150
precision highp float;
in Fragment
{
vec4 color;
} fragment;
out vec4 output_color;
void main(void)
{
output_color = fragment.color;
}
// Cell lighting Shader
// Vertex Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 150
precision highp float;
// Incoming per vertex... position and normal
in vec4 vVertex;
in vec3 vNormal;
uniform vec3 vLightPosition;
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform mat3 normalMatrix;
out Fragment
{
vec4 color;
} fragment;
void main(void)
{
// Get surface normal in eye coordinates
vec3 vEyeNormal = normalMatrix * vNormal;
// Get vertex position in eye coordinates
vec4 vPosition4 = mvMatrix * vVertex;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
// Get vector to light source
vec3 vLightDir = normalize(vLightPosition - vPosition3);
// Dot product gives us diffuse intensity
fragment.color = vec4(0.0, 0.0, 0.6, 1.0) * max(0.0, dot(vEyeNormal, vLightDir));
gl_Position = mvpMatrix * vVertex;
}
// Normal visualizer
// Fragment Shader
// Graham Sellers
// OpenGL SuperBible
#version 150
precision highp float;
in vec4 color;
out vec4 output_color;
void main(void)
{
output_color = color;
}
// Normal Visualizer
// Geometry Shader
// Graham Sellers
// OpenGL SuperBible
#version 150
precision highp float;
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
in Vertex
{
vec3 normal;
vec4 color;
} vertex[];
out vec4 color;
uniform vec3 vLightPosition;
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform mat3 normalMatrix;
uniform float push_out;
void main(void)
{
int n;
vec3 face_normal = normalize(cross(gl_in[1].gl_Position.xyz - gl_in[0].gl_Position.xyz,
gl_in[2].gl_Position.xyz - gl_in[0].gl_Position.xyz));
for (n = 0; n < gl_in.length(); n++) {
color = vertex[n].color;
gl_Position = mvpMatrix * vec4(gl_in[n].gl_Position.xyz + face_normal * push_out, gl_in[n].gl_Position.w);
EmitVertex();
}
EndPrimitive();
}
// Cell lighting Shader
// Vertex Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 150
precision highp float;
// Incoming per vertex... position and normal
in vec4 vVertex;
in vec3 vNormal;
out Vertex
{
vec3 normal;
vec4 color;
} vertex;
uniform vec3 vLightPosition;
uniform mat4 mvMatrix;
uniform mat3 normalMatrix;
void main(void)
{
// Get surface normal in eye coordinates
vec3 vEyeNormal = normalMatrix * vNormal;
// Get vertex position in eye coordinates
vec4 vPosition4 = mvMatrix * vVertex;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
// Get vector to light source
vec3 vLightDir = normalize(vLightPosition - vPosition3);
// Dot product gives us diffuse intensity
vertex.color = vec4(0.3, 0.3, 0.9, 1.0) * max(0.0, dot(vEyeNormal, vLightDir));
gl_Position = vVertex;
vertex.normal = vNormal;
}
// Geometry Shader 'Explode' Example
// OpenGL SuperBible 5th Edition
// Demonstrates 'explosion' of geometry using OpenGL geometry shaders
// Program by Graham Sellers
// OpenGL toolkit
#pragma comment(lib, "gltools.lib")
#include <GLTools.h>
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLGeometryTransform.h>
#include <Stopwatch.h>
#include <math.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
#ifdef _MSC_VER
#pragma comment (lib, "GLTools.lib")
#endif /* _MSC_VER */
static GLFrame viewFrame;
static GLFrustum viewFrustum;
static GLTriangleBatch torusBatch;
static GLMatrixStack modelViewMatrix;
static GLMatrixStack projectionMatrix;
static GLGeometryTransform transformPipeline;
static GLShaderManager shaderManager;
static GLuint explodeProgram; // The geometry shader 'exploder' program
static GLint locMVP; // The location of the ModelViewProjection matrix uniform
static GLint locMV; // The location of the ModelView matrix uniform
static GLint locNM; // The location of the Normal matrix uniform
static GLint locPushOut; // How far to push the geomery out
// This function does any needed initialization on the rendering context.
void SetupRC(void)
{
// Background
glClearColor(0.2f, 0.2f, 0.3f, 1.0f);
glEnable(GL_DEPTH_TEST);
shaderManager.InitializeStockShaders();
viewFrame.MoveForward(4.0f);
// Make the torus
gltMakeTorus(torusBatch, .70f, 0.10f, 11, 7);
explodeProgram = gltLoadShaderTripletWithAttributes("GSExplode.vs",
"GSExplode.gs",
"GSExplode.fs",
2,
GLT_ATTRIBUTE_VERTEX, "vVertex",
GLT_ATTRIBUTE_NORMAL, "vNormal");
locMVP = glGetUniformLocation(explodeProgram, "mvpMatrix");
locMV = glGetUniformLocation(explodeProgram, "mvMatrix");
locNM = glGetUniformLocation(explodeProgram, "normalMatrix");
locPushOut = glGetUniformLocation(explodeProgram, "push_out");
}
// Cleanup
void ShutdownRC(void)
{
glDeleteProgram(explodeProgram);
}
// Called to draw scene
void RenderScene(void)
{
static CStopWatch rotTimer;
// Clear the window and the depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
modelViewMatrix.PushMatrix(viewFrame);
modelViewMatrix.Rotate(rotTimer.GetElapsedSeconds() * 10.0f, 0.0f, 1.0f, 0.0f);
modelViewMatrix.Rotate(rotTimer.GetElapsedSeconds() * 13.0f, 1.0f, 0.0f, 0.0f);
GLfloat vEyeLight[] = { -100.0f, 100.0f, 100.0f };
GLfloat vAmbientColor[] = { 0.1f, 0.1f, 0.1f, 1.0f };
GLfloat vDiffuseColor[] = { 0.1f, 1.0f, 0.1f, 1.0f };
GLfloat vSpecularColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glUseProgram(explodeProgram);
glUniformMatrix4fv(locMVP, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
glUniformMatrix4fv(locMV, 1, GL_FALSE, transformPipeline.GetModelViewMatrix());
glUniformMatrix3fv(locNM, 1, GL_FALSE, transformPipeline.GetNormalMatrix());
float push_out = sinf(rotTimer.GetElapsedSeconds() * 3.0f) * 0.1f + 0.2f;
glUniform1f(locPushOut, push_out);
torusBatch.Draw();
modelViewMatrix.PopMatrix();
glutSwapBuffers();
glutPostRedisplay();
}
void ChangeSize(int w, int h)
{
// Prevent a divide by zero
if (h == 0)
h = 1;
// Set Viewport to window dimensions
glViewport(0, 0, w, h);
viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 100.0f);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
///
// Main entry point for GLUT based programs
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
glutInitWindowSize(800, 600);
glutCreateWindow("Geometry Shader Exploder");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
ShutdownRC();
return 0;
}