开发环境
Window7
CgToolkit
VS2008
羽化的第二十三篇博客,最近包括CSDN在内很多论坛遭受攻击,大家注意自己的要多注意自己的账户安全- -,话说这一年很快就要过去了,下一篇博客的前言是不是该写点年总结。。。最近工作很忙,羽化在写最终项目代码,目前基本上决定全用C#来写,尽力做到精致完美~ ~ 话说项目一下子来了两个策划,系统在慢慢搭建,虽然羽化不喜欢国内游戏制作的氛围,但这种应该还是可以慢慢改变,这次Cg的学习理论部分差不多结束了,下面都是代码操作,英语水平有限,请大家见谅,只能拿来看看概括,不能当作教程来学习,有兴趣的朋友还是去找找官方资料,详情请见Thinking in Shader(1)。
Introductionto CgFX 介绍CgFX
CgFx是Cg格式的延伸,添加进Cg程序中,CgFX文件也能代表固定管线图形状态和着色器源信息。CgFX API使他可以读取CgFX的特效文件,通过数据设置关联图形状态等等。关键概念包括:Effect、Technique、Pass、State assignment、Annotation、Effect parameter。
考虑下面特效:
//这个特效定义了一个简单参数,type只是为了程序方便调用,初始值是{1,1,1} 有一个限定范围
float3 DiffuseColor<string type = "color";
float3 minValue = float3(0,0,0);
float3 maxValue = float3(10,10,10);> = { 1, 1, 1 };
//这个特效还定义了一个方法,其中含有一个简单的渲染通道,这个通道设置适当的OpenGL状态来执行每个顶点光使用固定管线材质模型。注意LightDiffuse可以看出受散色光影响
technique FixedFunctionLighting
{
pass
{
LightingEnable = true;
LightEnable[0] = true;
LightPosition[0] = float4(-10, 10, 10, 1);
LightAmbient[0] = float4(.1,.1,.1,.1);
LightDiffuse[0] = (float4(2*DiffuseColor, 1));
LightSpecular[0] = float4(1,1,1,1);
MaterialShininess = 10.f;
MaterialAmbient = float4(1,1,1,1);
MaterialDiffuse = float4(.5, .5, .5, 1);
MaterialSpecular = float4(.5, .5, .5, 1);
}
}
下面是创建一个给定特效名字的程序:
CGcontext context = cgCreateContext(); //创建关联
cgGLRegisterStates(context); //创建OpenGL状态管理
CGeffect effect = cgCreateEffectFromFile(context, "simple.cgfx", NULL);
if (!effect)
{
fprintf(stderr, "Unable to create effect!\n");
const char *listing = cgGetLastListing(context);
if (listing)
fprintf(stderr, "%s\n", listing);
exit(1);
}
Technique Validation 技术验证
在使用任何技术在特效上时,都必须先验证下是否可用:
CGtechnique technique = cgGetFirstTechnique(effect);
while (technique)
{
if (cgValidateTechnique(technique) == CG_FALSE)
fprintf(stderr, "Technique %s did not validate. Skipping.\n",
cgGetTechniqueName(technique));
technique = cgGetNextTechnique(technique);
}
// cgIsTechniqueValidated() 一般用来检查
Passes and Pass State 通道和通道状态
在CgFX中允许一个通道状态定义在技术中:
CGpass pass = cgGetFirstPass(technique);
while (pass)
{
cgSetPassState(pass);
drawGeom();
cgResetPassState(pass);
pass = cgGetNextPass(pass);
}
Effect Parameters 特效参数
参数的句柄可以寻回使用cgGetNamedEffectParameter(),针对这个句柄,可以用cgGetParameterName()得到,值可以设置到程序入口:
CGparameter c = cgGetNamedEffectParameter(effect, "Color");
cgSetParameter3fv(c, Color);
CGparameter mvp = cgGetNamedEffectParameter(effect, "ModelViewProjection");
cgGLSetStateMatrixParameter(mvp, CG_GL_MODELVIEW_PROJECTION_MATRIX,
CG_GL_MATRIX_IDENTITY);
Vertex and Fragment Programs顶点和片段程序
通过OpenGL状态管理,顶点和片段程序定义分配给了顶点程序和片段程序状态,代表3个不同的类表达式可以分配给另一边:Compilestatements、In‐line assembly、NULL
float4 main(uniform float foo, float4 uv : TEXCOORD0) : COLOR
{
return (foo > 0) ? uv : 2 * uv;
}
technique SimpleFrag
{
pass
{
VertexProgram = NULL;
FragmentProgram = compile arbfp1 main(-2.f);
}
}
technique AsmFrag
{
pass
{
FragmentProgram = asm
{
!!FP1.0
TEX o[COLR], {0}.x, TEX6, 2D;
END
};
}
}
//另一个例子
float4 main(uniform float foo, float4 uv : TEXCOORD0) : COLOR
{
return (foo > 0) ? uv : 2 * uv;
}
float bar;
technique NewSimpleFrag
{
pass
{
VertexProgram = NULL;
FragmentProgram = compile arbfp1 main(2 * bar);// 2 * bar链接的是main中的参数
}
}
Textures and Samplers 贴图和采样器
CgFX使定义状态关联到贴图在特效文件中成为可能,例如:
sampler2D samp = sampler_state {
generateMipMap = true;
minFilter = LinearMipMapLinear;
magFilter = Linear;};
float4 texsimple(uniform sampler2D sampler,
float2 uv : TEXCOORD0) : COLOR {
return tex2D(sampler, uv);
}
technique TextureSimple {
pass
{
FragmentProgram = compile arbfp1 texsimple(samp);
}
}
得到这个特效文件,应用程序需要另外两步:1.应用必须表明哪张贴图处理需要sampler2D在特效文件中,2.应用程序必须使用Cg runtime设置贴图状态在适当的时间中给出到sampler_state 块中。最简单的方法是用cgGLSetupSampler(param, textureID)和初始化状态cgSetSamplerState()例如:
CGparameter p = cgGetNamedEffectParameter(effect, "samp");
GLuint handle;
glGenTextures(1, &handle);
glBindTexture(GL_TEXTURE_2D, handle);
cgGLSetTextureParameter(p, handle);
cgSetSamplerState(p);
...
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, RES, RES, 0, GL_RGBA,
GL_FLOAT, data);
//目前来看 最简单的设置管理贴图关联指令
cgGLSetManageTextureParameters(context, CG_TRUE);
CGparameter progParam = cgGetNamedParameter(prog, "sampler");
cgGLEnableTextureParameter(progParam);
Interfaces and Unsized Arrays接口和未知数组
//实例
interface Light
{
float4 value();
};
struct SpotLight : Light
{
float4 value() { return float4(1,2,3,4); }
};
float4 main(uniform Light l[]) : COLOR
{
float4 v = float4(0,0,0,0);
for (int i = 0; i < l.length; ++l)
v += l[i].value();
return v;
}
//解决光照使用Cg
SpotLight spots[4];
technique
{
pass
{
FragmentProgram = compile arbfp1 main(spots);
}
}
//解决光照使用Cg runtime
Light lights[];
technique
{
pass
{
FragmentProgram = compile arbfp1 main(lights);
}
}
//传递参数
CGtype spotType = cgGetNamedUserType(effect, "SpotLight");
CGparameter spots = cgCreateParameterArray(context, spotType, 4);
CGparameter lights = cgGetNamedEffectParameter(effect, "lights");
cgConnectParameter(spots, lights);
Evaluating Cg Programs using the Virtual Machine 用虚拟机评估Cg程序
很多情况下使用CPU来运行Cg程序在Cg runtime虚拟机上,CPU不提供一些GPU的功能,但有时很有用,在贴图索引中。
//在虚拟机中声明
float foo = 4.f;
float4 func(float2 p : POSITION, float2 delta : PSIZE) : COLOR
{
return foo * p.xyxy;
}
//使用CG_PROFILE_GENERIC配置文件
CGprogram tp = cgCreateProgramFromEffect(effect, CG_PROFILE_GENERIC, "func", NULL);
//cgEvaluateProgram评估程序
cgEvaluateProgram(Cgprogram prog, float *obuf, int ncomp,
int nx, int ny, int nz);
//设置缓冲
#define RES 256
#define NCOMPS 4
float *buf = new float[NCOMPS*RES*RES];
cgEvaluateProgram(tp, buf, NCOMPS, RES, RES, 1);
// do something with buf
delete[] buf;
Annotations 注释
使用注释能使参数信息更加明确,一个注释是一个可用数值列表,表示为<>尖括号
float3 LightDir < string UItype = "direction"; >;
technique fancyHalo <bool optional = true;> {
pass < string geometry = "character"; string destination = "texture"; > {
...
}
}
//给一个句柄,这样通过API可以拿到
CGannotation cgGetFirstTechniqueAnnotation(CGtechnique);
CGannotation cgGetFirstPassAnnotation(CGpass);
CGannotation cgGetFirstParameterAnnotation(CGparameter);
CGannotation cgGetFirstProgramAnnotation(CGprogram);
CGannotation cgGetNextAnnotation(CGannotation);
Gannotation cgGetNamedTechniqueAnnotation(CGtechnique, const char *);
CGannotation cgGetNamedPassAnnotation(CGpass, const char *);
CGannotation cgGetNamedParameterAnnotation(CGparameter, const char *);
CGannotation cgGetNamedProgramAnnotation(CGprogram, const char *);
const float *cgGetFloatAnnotationValues(CGannotation, int *nvalues);
const int *cgGetIntAnnotationValues(CGannotation, int *nvalues);
const char *cgGetStringAnnotationValue(CGannotation);
const int *cgGetBooleanAnnotationValues(CGannotation, int *nvalues);
OpenGL State 和 OpenGL SamplerState
主要左右还是调试上,对应几张很长很长的表,具体可以详见CgUsersManual文档。。。
差不多这里把OpenGL和Direct3D的基本调用说了下,下次应该送上在公司没事做的一个骨骼动力学,比较简陋,大家将就看吧- -
下期预告:
Unity骨骼动力学应用