Thinking in Shader(6)
Thinking in Shader(6)
开发环境
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);
- }
- }
//这个特效定义了一个简单参数,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);
- }
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() 一般用来检查
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);
- }
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);
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中的参数
- }
- }
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);
- }
- }
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);
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);
//实例 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;
//在虚拟机中声明 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);
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骨骼动力学应用