先来个比较简单的shader作为3Dshader的开篇之作吧

物体的膨胀与收缩

国际惯例,先贴效果图,无图无真相

1.茶壶原始尺寸

2.茶壶膨胀

3.茶壶收缩

收缩不是很明显,因为收缩太多,茶壶里外面对兑,看起来很别扭,不相信?跟你们来一张吧

好了,讲下原理

我们知道一个物体是由很多顶点构成的,每个顶点都有法向量,把物体的顶点按法向量向外移动一段距离,那么物体就会膨胀,相反向内移动一段距离,物体就会收缩.就这么简单

下面给出源码:

main.cpp文件

//1 add Cg Frame
//2 add fragment program
//3 get and set uniform variables in vertex shader and fragment shader
#include <stdio.h>
#include <stdlib.h>
#include <cg/cg.h>
#include <cg/cgGL.h>
#include <gl/glut.h>
#include <cassert>
#include <cmath>
static CGcontext myCgContext;
static CGprofile myCgVertexProfile;
static CGprogram myCgVertexProgram;
//2 begin
static CGprofile myCgFragmentProfile;
static CGprogram myCgFragmentProgram;
//2 end
static const char* myProgramName="explosion & shrinkage";
static const char* myVertexProgramFileName="MyVertex.cg";
static const char* myVertexProgramEntryFunctionName="MyVertexEntry";
//2 begin
static const char* myFragmentProgramFileName="MyFragment.cg";
static const char* myFragmentProgramEntryFunctionName="MyFragmentEntry";
//2 end
//3 begin
static CGparameter myCgVertexParam_modelViewProj,
myCgVertexParam_factor,
myCgFragmentParam_globalAmbient,
myCgFragmentParam_lightColor,
myCgFragmentParam_lightPosition,
myCgFragmentParam_eyePosition,
myCgFragmentParam_Ke,
myCgFragmentParam_Ka,
myCgFragmentParam_Kd,
myCgFragmentParam_Ks,
myCgFragmentParam_shininess;;
static float myfactor=0;
static float myLightAngle = -0.4;   /* Angle light rotates around scene. */
static float myProjectionMatrix[16];
static float myGlobalAmbient[3] = { 0.1, 0.1, 0.1 };  /* Dim */
static float myLightColor[3] = { 0.95, 0.95, 0.95 };  /* White */
//3 end
static void checkForCgError(const char *situation)
{
CGerror error;
const char *string = cgGetLastErrorString(&error);
if (error != CG_NO_ERROR)
{
printf("%s: %s: %s\n",myProgramName, situation, string);
if (error == CG_COMPILER_ERROR)
printf("%s\n", cgGetLastListing(myCgContext));
exit(1);
}
}
static void display(void);
static void keyboard(unsigned char c,int x,int y);
static void reshape(int width, int height);
int main(int argc,char **argv)
{
glutInitWindowSize(400,400);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInit(&argc,argv);
glutCreateWindow(myProgramName);//窗口名字为我们的程序名字
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutReshapeFunc(reshape);
glClearColor(0.1,0.3,0.6,0.0);
glEnable(GL_DEPTH_TEST);//重要
myCgContext=cgCreateContext();
checkForCgError("creating context");
cgGLSetDebugMode(CG_FALSE);
cgSetParameterSettingMode(myCgContext,CG_DEFERRED_PARAMETER_SETTING);
myCgVertexProfile=cgGLGetLatestProfile(CG_GL_VERTEX);
cgGLSetOptimalOptions(myCgVertexProfile);
checkForCgError("selecting vertex profile");
myCgVertexProgram=cgCreateProgramFromFile(
myCgContext,CG_SOURCE,myVertexProgramFileName,myCgVertexProfile,myVertexProgramEntryFunctionName,NULL);
checkForCgError("creating vertex program from file");
cgGLLoadProgram(myCgVertexProgram);
checkForCgError("loading vertex program");
//3 begin
#define GET_VERTEX_PARAM(name) \
myCgVertexParam_##name = \
cgGetNamedParameter(myCgVertexProgram, #name); \
checkForCgError("could not get " #name " parameter");
GET_VERTEX_PARAM(modelViewProj);
GET_VERTEX_PARAM(factor);
//3 end
//2 begin
myCgFragmentProfile=cgGLGetLatestProfile(CG_GL_FRAGMENT);
cgGLSetOptimalOptions(myCgFragmentProfile);
checkForCgError("selecting fragment profile");
myCgFragmentProgram=cgCreateProgramFromFile(
myCgContext,CG_SOURCE,myFragmentProgramFileName,myCgFragmentProfile,myFragmentProgramEntryFunctionName,NULL);
checkForCgError("creating fragment program from file");
cgGLLoadProgram(myCgFragmentProgram);
checkForCgError("loading fragment program");
//2 end
//3 begin
#define GET_FRAGMENT_PARAM(name) \
myCgFragmentParam_##name = \
cgGetNamedParameter(myCgFragmentProgram, #name); \
checkForCgError("could not get " #name " parameter");
GET_FRAGMENT_PARAM(globalAmbient);
GET_FRAGMENT_PARAM(lightColor);
GET_FRAGMENT_PARAM(lightPosition);
GET_FRAGMENT_PARAM(eyePosition);
GET_FRAGMENT_PARAM(Ke);
GET_FRAGMENT_PARAM(Ka);
GET_FRAGMENT_PARAM(Kd);
GET_FRAGMENT_PARAM(Ks);
GET_FRAGMENT_PARAM(shininess);
cgSetParameter3fv(myCgFragmentParam_globalAmbient, myGlobalAmbient);
cgSetParameter3fv(myCgFragmentParam_lightColor, myLightColor);
//3 end
glutMainLoop();
return 0;
}
//3 begin
/* Forward declared routine used by reshape callback. */
static void buildPerspectiveMatrix(double fieldOfView,
double aspectRatio,
double zMin, double zMax,
float m[16]);
static void reshape(int width, int height)
{
double aspectRatio = (float) width / (float) height;
double fieldOfView = 40.0; /* Degrees */
/* Build projection matrix once. */
buildPerspectiveMatrix(fieldOfView, aspectRatio,
1.0, 100.0,  /* Znear and Zfar */
myProjectionMatrix);
glViewport(0, 0, width, height);
}
static const double myPi = 3.14159265358979323846;
/* Build a row-major (C-style) 4x4 matrix transform based on the
parameters for gluPerspective. */
static void buildPerspectiveMatrix(double fieldOfView,
double aspectRatio,
double zNear, double zFar,
float m[16])
{
double sine, cotangent, deltaZ;
double radians = fieldOfView / 2.0 * myPi / 180.0;
deltaZ = zFar - zNear;
sine = sin(radians);
/* Should be non-zero to avoid division by zero. */
assert(deltaZ);
assert(sine);
assert(aspectRatio);
cotangent = cos(radians) / sine;
m[0*4+0] = cotangent / aspectRatio;
m[0*4+1] = 0.0;
m[0*4+2] = 0.0;
m[0*4+3] = 0.0;
m[1*4+0] = 0.0;
m[1*4+1] = cotangent;
m[1*4+2] = 0.0;
m[1*4+3] = 0.0;
m[2*4+0] = 0.0;
m[2*4+1] = 0.0;
m[2*4+2] = -(zFar + zNear) / deltaZ;
m[2*4+3] = -2 * zNear * zFar / deltaZ;
m[3*4+0] = 0.0;
m[3*4+1] = 0.0;
m[3*4+2] = -1;
m[3*4+3] = 0;
}
static void buildLookAtMatrix(double eyex, double eyey, double eyez,
double centerx, double centery, double centerz,
double upx, double upy, double upz,
float m[16])
{
double x[3], y[3], z[3], mag;
/* Difference eye and center vectors to make Z vector. */
z[0] = eyex - centerx;
z[1] = eyey - centery;
z[2] = eyez - centerz;
/* Normalize Z. */
mag = sqrt(z[0]*z[0] + z[1]*z[1] + z[2]*z[2]);
if (mag) {
z[0] /= mag;
z[1] /= mag;
z[2] /= mag;
}
/* Up vector makes Y vector. */
y[0] = upx;
y[1] = upy;
y[2] = upz;
/* X vector = Y cross Z. */
x[0] =  y[1]*z[2] - y[2]*z[1];
x[1] = -y[0]*z[2] + y[2]*z[0];
x[2] =  y[0]*z[1] - y[1]*z[0];
/* Recompute Y = Z cross X. */
y[0] =  z[1]*x[2] - z[2]*x[1];
y[1] = -z[0]*x[2] + z[2]*x[0];
y[2] =  z[0]*x[1] - z[1]*x[0];
/* Normalize X. */
mag = sqrt(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]);
if (mag) {
x[0] /= mag;
x[1] /= mag;
x[2] /= mag;
}
/* Normalize Y. */
mag = sqrt(y[0]*y[0] + y[1]*y[1] + y[2]*y[2]);
if (mag) {
y[0] /= mag;
y[1] /= mag;
y[2] /= mag;
}
/* Build resulting view matrix. */
m[0*4+0] = x[0];  m[0*4+1] = x[1];
m[0*4+2] = x[2];  m[0*4+3] = -x[0]*eyex + -x[1]*eyey + -x[2]*eyez;
m[1*4+0] = y[0];  m[1*4+1] = y[1];
m[1*4+2] = y[2];  m[1*4+3] = -y[0]*eyex + -y[1]*eyey + -y[2]*eyez;
m[2*4+0] = z[0];  m[2*4+1] = z[1];
m[2*4+2] = z[2];  m[2*4+3] = -z[0]*eyex + -z[1]*eyey + -z[2]*eyez;
m[3*4+0] = 0.0;   m[3*4+1] = 0.0;  m[3*4+2] = 0.0;  m[3*4+3] = 1.0;
}
static void normalizeVector(float v[3])
{
float mag;
mag = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
if (mag) {
float oneOverMag = 1.0 / mag;
v[0] *= oneOverMag;
v[1] *= oneOverMag;
v[2] *= oneOverMag;
}
}
static void makeRotateMatrix(float angle,
float ax, float ay, float az,
float m[16])
{
float radians, sine, cosine, ab, bc, ca, tx, ty, tz;
float axis[3];
axis[0] = ax;
axis[1] = ay;
axis[2] = az;
normalizeVector(axis);
radians = angle * myPi / 180.0;
sine = sin(radians);
cosine = cos(radians);
ab = axis[0] * axis[1] * (1 - cosine);
bc = axis[1] * axis[2] * (1 - cosine);
ca = axis[2] * axis[0] * (1 - cosine);
tx = axis[0] * axis[0];
ty = axis[1] * axis[1];
tz = axis[2] * axis[2];
m[0]  = tx + cosine * (1 - tx);
m[1]  = ab + axis[2] * sine;
m[2]  = ca - axis[1] * sine;
m[3]  = 0.0f;
m[4]  = ab - axis[2] * sine;
m[5]  = ty + cosine * (1 - ty);
m[6]  = bc + axis[0] * sine;
m[7]  = 0.0f;
m[8]  = ca + axis[1] * sine;
m[9]  = bc - axis[0] * sine;
m[10] = tz + cosine * (1 - tz);
m[11] = 0;
m[12] = 0;
m[13] = 0;
m[14] = 0;
m[15] = 1;
}
/* Build a row-major (C-style) 4x4 matrix transform based on the
parameters for glTranslatef. */
static void makeTranslateMatrix(float x, float y, float z, float m[16])
{
m[0]  = 1;  m[1]  = 0;  m[2]  = 0;  m[3]  = x;
m[4]  = 0;  m[5]  = 1;  m[6]  = 0;  m[7]  = y;
m[8]  = 0;  m[9]  = 0;  m[10] = 1;  m[11] = z;
m[12] = 0;  m[13] = 0;  m[14] = 0;  m[15] = 1;
}
/* Simple 4x4 matrix by 4x4 matrix multiply. */
static void multMatrix(float dst[16],
const float src1[16], const float src2[16])
{
float tmp[16];
int i, j;
for (i=0; i<4; i++) {
for (j=0; j<4; j++) {
tmp[i*4+j] = src1[i*4+0] * src2[0*4+j] +
src1[i*4+1] * src2[1*4+j] +
src1[i*4+2] * src2[2*4+j] +
src1[i*4+3] * src2[3*4+j];
}
}
/* Copy result to dst (so dst can also be src1 or src2). */
for (i=0; i<16; i++)
dst[i] = tmp[i];
}
static void invertMatrix(float *out, const float *m)
{
/* Assumes matrices are ROW major. */
#define SWAP_ROWS(a, b) { GLdouble *_tmp = a; (a)=(b); (b)=_tmp; }
#define MAT(m,r,c) (m)[(r)*4+(c)]
double wtmp[4][8];
double m0, m1, m2, m3, s;
double *r0, *r1, *r2, *r3;
r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
r0[0] = MAT(m,0,0), r0[1] = MAT(m,0,1),
r0[2] = MAT(m,0,2), r0[3] = MAT(m,0,3),
r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0,
r1[0] = MAT(m,1,0), r1[1] = MAT(m,1,1),
r1[2] = MAT(m,1,2), r1[3] = MAT(m,1,3),
r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0,
r2[0] = MAT(m,2,0), r2[1] = MAT(m,2,1),
r2[2] = MAT(m,2,2), r2[3] = MAT(m,2,3),
r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0,
r3[0] = MAT(m,3,0), r3[1] = MAT(m,3,1),
r3[2] = MAT(m,3,2), r3[3] = MAT(m,3,3),
r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0;
/* Choose myPivot, or die. */
if (fabs(r3[0])>fabs(r2[0])) SWAP_ROWS(r3, r2);
if (fabs(r2[0])>fabs(r1[0])) SWAP_ROWS(r2, r1);
if (fabs(r1[0])>fabs(r0[0])) SWAP_ROWS(r1, r0);
if (0.0 == r0[0]) {
assert(!"could not invert matrix");
}
/* Eliminate first variable. */
m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0];
s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s;
s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s;
s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s;
s = r0[4];
if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; }
s = r0[5];
if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; }
s = r0[6];
if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; }
s = r0[7];
if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; }
/* Choose myPivot, or die. */
if (fabs(r3[1])>fabs(r2[1])) SWAP_ROWS(r3, r2);
if (fabs(r2[1])>fabs(r1[1])) SWAP_ROWS(r2, r1);
if (0.0 == r1[1]) {
assert(!"could not invert matrix");
}
/* Eliminate second variable. */
m2 = r2[1]/r1[1]; m3 = r3[1]/r1[1];
r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2];
r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3];
s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; }
s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; }
s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; }
s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; }
/* Choose myPivot, or die. */
if (fabs(r3[2])>fabs(r2[2])) SWAP_ROWS(r3, r2);
if (0.0 == r2[2]) {
assert(!"could not invert matrix");
}
/* Eliminate third variable. */
m3 = r3[2]/r2[2];
r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6],
r3[7] -= m3 * r2[7];
/* Last check. */
if (0.0 == r3[3]) {
assert(!"could not invert matrix");
}
s = 1.0/r3[3];              /* Now back substitute row 3. */
r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s;
m2 = r2[3];                 /* Now back substitute row 2. */
s  = 1.0/r2[2];
r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
m1 = r1[3];
r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
m0 = r0[3];
r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
m1 = r1[2];                 /* Now back substitute row 1. */
s  = 1.0/r1[1];
r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
m0 = r0[2];
r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
m0 = r0[1];                 /* Now back substitute row 0. */
s  = 1.0/r0[0];
r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
MAT(out,0,0) = r0[4]; MAT(out,0,1) = r0[5],
MAT(out,0,2) = r0[6]; MAT(out,0,3) = r0[7],
MAT(out,1,0) = r1[4]; MAT(out,1,1) = r1[5],
MAT(out,1,2) = r1[6]; MAT(out,1,3) = r1[7],
MAT(out,2,0) = r2[4]; MAT(out,2,1) = r2[5],
MAT(out,2,2) = r2[6]; MAT(out,2,3) = r2[7],
MAT(out,3,0) = r3[4]; MAT(out,3,1) = r3[5],
MAT(out,3,2) = r3[6]; MAT(out,3,3) = r3[7];
#undef MAT
#undef SWAP_ROWS
}
static void transform(float dst[4],
const float mat[16], const float vec[4])
{
double tmp[4], invW;
int i;
for (i=0; i<4; i++) {
tmp[i] = mat[i*4+0] * vec[0] +
mat[i*4+1] * vec[1] +
mat[i*4+2] * vec[2] +
mat[i*4+3] * vec[3];
}
invW = 1 / tmp[3];
/* Apply perspective divide and copy to dst (so dst can vec). */
for (i=0; i<3; i++)
dst[i] = tmp[i] * tmp[3];
dst[3] = 1;
}
void setTeapotMaterial()
{
const float brassEmissive[3] = {0.0,  0.0,  0.0},
brassAmbient[3]  = {0.33, 0.22, 0.03},
brassDiffuse[3]  = {0.78, 0.57, 0.11},
brassSpecular[3] = {0.99, 0.91, 0.81},
brassShininess = 27.8;
cgSetParameter3fv(myCgFragmentParam_Ke, brassEmissive);
cgSetParameter3fv(myCgFragmentParam_Ka, brassAmbient);
cgSetParameter3fv(myCgFragmentParam_Kd, brassDiffuse);
cgSetParameter3fv(myCgFragmentParam_Ks, brassSpecular);
cgSetParameter1f(myCgFragmentParam_shininess, brassShininess);
}
static void display(void)
{
//3 begin
/* World-space positions for light and eye. */
const float eyePosition[4] = { 0, 0, 13, 1 };
const float lightPosition[4] = { 5*sin(myLightAngle),
1.5,
5*cos(myLightAngle), 1 };
float translateMatrix[16], rotateMatrix[16],
modelMatrix[16], invModelMatrix[16], viewMatrix[16],
modelViewMatrix[16], modelViewProjMatrix[16];
float objSpaceEyePosition[4], objSpaceLightPosition[4];
buildLookAtMatrix(eyePosition[0], eyePosition[1], eyePosition[2],
0, 0, 0,
0, 1, 0,
viewMatrix);
//3 end
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
cgGLBindProgram(myCgVertexProgram);
checkForCgError("binding vertex program");
cgGLEnableProfile(myCgVertexProfile);
checkForCgError("enabling vertex profile");
//2 begin
cgGLBindProgram(myCgFragmentProgram);
checkForCgError("binding fragment program");
cgGLEnableProfile(myCgFragmentProfile);
checkForCgError("enabling fragment profile");
//2 end
setTeapotMaterial();
makeTranslateMatrix(0,-2,0,translateMatrix);
makeRotateMatrix(90,1,0,0,rotateMatrix);
multMatrix(modelMatrix,translateMatrix,rotateMatrix);
invertMatrix(invModelMatrix, modelMatrix);
transform(objSpaceEyePosition, invModelMatrix, eyePosition);
cgSetParameter3fv(myCgFragmentParam_eyePosition, objSpaceEyePosition);
transform(objSpaceLightPosition, invModelMatrix, lightPosition);
cgSetParameter3fv(myCgFragmentParam_lightPosition, objSpaceLightPosition);
multMatrix(modelViewMatrix, viewMatrix, modelMatrix);
multMatrix(modelViewProjMatrix, myProjectionMatrix, modelViewMatrix);
cgSetMatrixParameterfr(myCgVertexParam_modelViewProj, modelViewProjMatrix);
cgSetParameter1f(myCgVertexParam_factor,myfactor);
cgUpdateProgramParameters(myCgVertexProgram);
cgUpdateProgramParameters(myCgFragmentProgram);
glutSolidTeapot(2);
cgGLDisableProfile(myCgVertexProfile);
checkForCgError("disabling vertex profile");
//2 begin
cgGLDisableProfile(myCgFragmentProfile);
checkForCgError("disabling fragment profile");
//2 end
glutSwapBuffers();
}
static int direction = 1;
static void idle(void)
{
myfactor +=direction*0.01;  /* Add a small angle (in radians). */
if (myfactor > 1)
{
direction = -1;
}
else if(myfactor < -0.1)
{
direction = 1;
}
/*
myLightAngle += 0.008;
if (myLightAngle > 2*myPi) {
myLightAngle -= 2*myPi;
}*/
glutPostRedisplay();
}
static void keyboard(unsigned char c,int x,int y)
{
static int animating = 0;
switch(c)
{
case ' ':
animating = !animating; /* Toggle */
if (animating) {
glutIdleFunc(idle);
} else {
glutIdleFunc(NULL);
}
break;
case 27:
cgDestroyProgram(myCgVertexProgram);
cgDestroyContext(myCgContext);
exit(0);
break;
}
}

MyVertex.cg文件

void MyVertexEntry(float4 position:POSITION,
float3 normal:NORMAL,
out float4 oPosition:POSITION,
out float4 objectPos : TEXCOORD0,
out float3 oNormal   : TEXCOORD1,
uniform float4x4 modelViewProj,
uniform float factor
)
{
float4 pos=position + float4(normal,1)*factor*0.3;
pos.w=1;
oPosition = mul(modelViewProj, pos);
objectPos=pos;
oNormal=normal;
}

MyFragment.cg文件

void MyFragmentEntry(float4 position  : TEXCOORD0,
float3 normal    : TEXCOORD1,
out float4 color     : COLOR,
uniform float3 globalAmbient,
uniform float3 lightColor,
uniform float3 lightPosition,
uniform float3 eyePosition,
uniform float3 Ke,
uniform float3 Ka,
uniform float3 Kd,
uniform float3 Ks,
uniform float  shininess)
{
float3 P = position.xyz;
float3 N = normalize(normal);
// Compute emissive term
float3 emissive = Ke;
// Compute ambient term
float3 ambient = Ka * globalAmbient;
// Compute the diffuse term
float3 L = normalize(lightPosition - P);
float diffuseLight = max(dot(L, N), 0);
float3 diffuse = Kd * lightColor * diffuseLight;
// Compute the specular term
float3 V = normalize(eyePosition - P);
float3 H = normalize(L + V);
float specularLight = pow(max(dot(H, N), 0), shininess);
if (diffuseLight <= 0) specularLight = 0;
float3 specular = Ks * lightColor * specularLight;
color.xyz = emissive + ambient + diffuse + specular;
color.w = 1;
}

相关可执行文件及源程序请点这里下载

好了,第一个shader就这样吧, 得抓紧了,准备搞个hdr的shader出来

3Dshader之膨胀与收缩相关推荐

  1. 数字图像处理:腐蚀与膨胀操作

    腐蚀与膨胀是数字形态学中的基本操作,一般用在二值图像(二值图像指每个像素不是黑就是白,其灰度值没有中间过渡的图像.),不过用在RGB图像上也是可以的. 灰度图:任何颜色都有红.绿.蓝三原色组成,而灰度 ...

  2. 【Unity3D】基于模板测试和顶点膨胀的描边方法

    1 前言 选中物体描边特效 中介绍了基于模板纹理模糊膨胀的描边方法,该方法实现了软描边,效果较好,但是为了得到模糊纹理,对屏幕像素进行了多次渲染,效率欠佳.本文将介绍另一种描边方法:基于模板测试和顶点 ...

  3. 透视宇宙:大约138亿年前,宇宙真的发生过大爆炸吗?

    撰文 | [日]小柴昌俊 摘编丨何安安 来源 | 新京报书评周刊(ID:ibookreview) 如何用新思维去认识宇宙?如果用可以穿透一切物质的中微子来透视宇宙深处,将会看到什么?小柴昌俊在他的科普 ...

  4. 宇宙是一个无始无终的循环?

    图片来源:Samuel Velasco/Quanta Magazine 最近,科学家通过复杂的计算机模拟发现,除了宇宙暴胀,宇宙收缩同样可以创造出今天我们所见宇宙的种种特征.并且在循环宇宙中,膨胀和收 ...

  5. 距离和相似性度量方法

    目录 1. 闵可夫斯基距离:欧几里得距离.曼哈顿距离.切比雪夫距离 2. 马氏距离 3. 向量内积:余弦相似度.皮尔逊相关系数 4. 分类数据点间的距离:汉明距离.杰卡德相似系数 5. 序列之间的距离 ...

  6. python前缀表达式求值_python数据结构与算法 11 后缀表达式求值

    从本节开始,删除原版的英文,直接发译后的文稿. 后缀表达式求值 栈的最一个应用例子,计算一个后缀表达式的值.这个例子中仍然用栈的数据结构.不过,当扫描表达式的时候,这次是操作数压栈等待,不是转换算法中 ...

  7. 漫谈:机器学习中距离和相似性度量方法

    在机器学习和数据挖掘中,我们经常需要知道个体间差异的大小,进而评价个体的相似性和类别.最常见的是数据分析中的相关分析,数据挖掘中的分类和聚类算法,如 K 最近邻(KNN)和 K 均值(K-Means) ...

  8. 抢红包的红包生成算法

    过年微信红包很火,最近有个项目也要做抢红包,于是写了个红包的生成算法. 红包生成算法的需求 预先生成所有的红包还是一个请求随机生成一个红包 简单来说,就是把一个大整数m分解(直接以"分为单位 ...

  9. 机器学习中距离和相似性度量方法

    在机器学习和数据挖掘中,我们经常需要知道个体间差异的大小,进而评价个体的相似性和类别.最常见的是数据分析中的相关分析,数据挖掘中的分类和聚类算法,如 K 最近邻(KNN)和 K 均值(K-Means) ...

最新文章

  1. MATLAB_no.2:关于眼睛的_cutab=[cutab;a b];_cutab(:,2)-cutab(:,1):
  2. DeepMind提出强化学习新方法,可实现人机合作
  3. 中国工程院2021年院士增选第二轮候选人名单公布
  4. 英雄会解读:不一样的回答,一样的CTO
  5. 把数据转换为在内存中Tree(树形结构)。_Linux的中断处理机制 [二] - 数据结构(2)...
  6. 【原创】CSSOO的思想及CSS框架的应用(未整理完)
  7. JAVA_OA(八):springMVC对JDBC的操作小项目b
  8. 如何判断程序员是在装逼还是有真本事?
  9. php date 有warning,PHP Warning: strtotime()错误解决办法
  10. 苹果iOS 14系统面板截图曝光:加入新墙纸设置
  11. 【kafka】消费组 死掉 kafka Marking the coordinator dead for group
  12. 软件设计师10-面向对象-设计模式
  13. 启动项目无法打印日志处理及logback简单使用
  14. vs2017远程编译linux教程,Visual Studio 2017 远程编译调试 Linux 上已存在的通过 Samba 共享的 CMake 工程...
  15. SQLite实现在线电子词典
  16. 平面应变四节点matlab,matlab-四节点四边形等参元的刚度矩阵计算程序.doc
  17. 沉没成本---欲罢不能的困局?
  18. 李大狗:从 Logo, Basic 到区块链 - Mixin Network 开发者访谈系列 第二期
  19. CMSC5713-IT项目管理之四、项目规划Project Planning
  20. 随身WIFI安装Debian流程记录

热门文章

  1. QByteArray与char、int、float(及其数组)之间的互相转化
  2. layui如何获取父节点的父节点_layui树形组件(右键、父节点选中子节点全被选中)...
  3. node.js创建server
  4. 安装和使用memcached
  5. 09hibernate_session_flush
  6. 关于Ip地址分配规则(IPV4)
  7. 华为机试HJ5:进制转换
  8. matlab显示灰度值的概率,求Matlab统计灰度值的代码
  9. android小球移动代码,Android中如何绘制一个跟随手指移动的小球
  10. 微信分身版电脑版_电脑版营销wetool电脑版-网站