Thinking in Shader(4)
Thinking in Shader(4)
开发环境
Window7
CgToolkit
VS2008
羽化的第二十篇博客,没想到写到二十篇了,送上有点稍晚,Cg基础部分学得或多或少了,不出意外下周开始学写Cg代码了,到时候再慢慢更新在博客上,由于明哥的给力我们的地图终于支持到了6层,正在向无限层发起挑战,明哥钢霸得。。。这周翻了地牢围攻3,很精美的一款游戏,2代可以说是羽化玩过的仅次于暗黑的相同类型游戏,3代由于加入Square制作后,技术明显提升,各种Flare应用得淋漓尽致,但没了原来的朴实与多样性,彻头彻尾变成了另一个游戏。。。话说波仔被车撞了,也就是上周的事情,知道以后些许担心,但也有些许气愤,作为在上海唯一的老乡朋友,居然不告诉我。。。但幸好没事,依然和我们犀利dota- - 工作越来越忙,人手不足一直是个很头疼的问题,况且大家都没这方面经验,作为公司的第一个Unity游戏,居然做成MMORPG类型,其实羽化虽然信心满满,但总会遇到很多无法预料的问题,还是太弱了。。。
发个牢骚(以下为个人意见):其实羽化一直搞不懂,为什么一个游戏公司养这么多策划,羽化认为策划应该是一个高层次的职业少而精,对应文艺或者设计方面的人才,能提供有价值的参考和规定制作的核心内容:游戏系统、场景、剧情、数值调整等复杂设定,但现在的公司里策划却能每天悠然自得,竟是些看漫画、看电影、打游戏、吃吃零食的空虚年轻人,策划需要丰富的阅历和灵感不错,但不是玩玩国内的垃圾游戏(国内也有很多好作品,但大多数是仿制的垃圾),看几部贺岁电影能培养出来的。。。做一个MMO就想仿照魔兽世界,又搞些多余的休闲方式和活动,这样根本无法超越它,这可能就是国内游戏缺少创新的主要原因,也和这个利益社会有关系吧。羽化认为国内很少有游戏制作人这种说法,制作人应该置于策划,高于策划,控制整个游戏的制作内容而不是规定游戏的制作方式,由于缺少一个与程序、美术、策划三方交流的核心,所以经常是一堆空虚的策划在一起商量一些大家都懂的常识问题,于是又一款山寨游戏就这此诞生了。总的一句话:策划这职业不是什么人都能当的,国内的策划伤不起- -
Cg代码使用代码来描述材质,但是他们需要应用程序的支持来创建图像。在Cg的程序界面,你必须做两件事:
1. 为正确的配置编译程序,换句话说,就是我们要编译程序按照特点定的3D API的应用程序和底层硬件配置。
2. 连接程序在应用中,使其允许应用程序支持不同的和统一的数据接口给程序。
你有两种方式执行他们,一种是当应用程序编译在一个可执行文件中的时候,另一种是在运行的时候,应用程序在执行的时候。Cg Runtime是一个应用程序接口,允许Cg程序在运行时编译和链接。其优势在于未来的兼容性,没有依赖限制,输入参数管理三个方面。
Header Files 头文件
要引用Cg runtimeAPI在C或者C++中,头文件有以下几种:
- 核心: #include <Cg/cg.h>
- OpenGL: #include <Cg/cgGL.h>
- Direct3D 9: #include <Cg/cgD3D9.h>
- Direct3D 8: #include <Cg/cgD3D8.h>
核心: #include <Cg/cg.h> OpenGL: #include <Cg/cgGL.h> Direct3D 9: #include <Cg/cgD3D9.h> Direct3D 8: #include <Cg/cgD3D8.h>
Creating a Context 创建关联
一个Context是一个容器包含多个Cg程序,他保存Cg程序就像分享数据意义。下面是创建方法:
- CGcontext context = cgCreateContext();
CGcontext context = cgCreateContext();
Compiling a Program 编译程序
编译Cg程序通过添加一个Context通过cgCreateProgram():
- CGprogram program = cgCreateProgram(context,CG_SOURCE, myVertexProgramString,CG_PROFILE_ARBVP1, "main", args);
CGprogram program = cgCreateProgram(context,CG_SOURCE, myVertexProgramString,CG_PROFILE_ARBVP1, "main", args);
CG_SOURCE表明myVertexProgramString,一个string类型参数,包含Cg起源代码,没有预先编译代码,甚至如果你想,Cg runtime允许你创建一个程序来预编译。
CG_PROFILE_ARBVP1是一个表面的编译程序,“main”参数给这个功能命名作为入口当程序运行时,最后args是一个空字符串的空列表,可以传递一个参数来编译。
Loading a Program 加载程序
- //在Direct3D首先设置硬件
- cgD3D9SetDevice(Device);
- //下面读取Direct3D 9 Cg Runtime:
- cgD3D9LoadProgram(program, CG_FALSE, 0);
- //或者Direct3D 8 Cg Runtime:
- cgD3D8LoadProgram(program, CG_FALSE, 0, 0, vertexDeclaration);
- //在OpenGL则是
- cgGLLoadProgram(program);
//在Direct3D首先设置硬件 cgD3D9SetDevice(Device); //下面读取Direct3D 9 Cg Runtime: cgD3D9LoadProgram(program, CG_FALSE, 0); //或者Direct3D 8 Cg Runtime: cgD3D8LoadProgram(program, CG_FALSE, 0, 0, vertexDeclaration); //在OpenGL则是 cgGLLoadProgram(program);
Modifying Program Parameters 参数修改
想修改参数,第一步先获得句柄:
- CGparameter myParameter = cgGetNamedParameter(program, "myParameter");
CGparameter myParameter = cgGetNamedParameter(program, "myParameter");
myParameter是源文件中出现的参数。
第二步是设定一个参数值,这个功能取决于参数类型,下面是个例子:
- cgGLSetParameter4fv(myParameter, value); //OpenGL
- cgD3D9SetUniform(myParameter, value); //Direct3D
- cgSetParameterValuefr(myParameter, 4, value); //数值参数可以通过Cg Runtime获得,这是被假定为一个float4类型参数
cgGLSetParameter4fv(myParameter, value); //OpenGL cgD3D9SetUniform(myParameter, value); //Direct3D cgSetParameterValuefr(myParameter, 4, value); //数值参数可以通过Cg Runtime获得,这是被假定为一个float4类型参数
Executing a Program 执行程序
先设置配置文件,Direct3D中没有明确的配置。
- cgGLEnableProfile(CG_PROFILE_ARBVP1); //OpenGL
- cgGLDisableProfile(CG_PROFILE_ARBVP1); //相反
cgGLEnableProfile(CG_PROFILE_ARBVP1); //OpenGL cgGLDisableProfile(CG_PROFILE_ARBVP1); //相反
下面是绑定程序:
- cgGLBindProgram(program); // OpenGL
- cgD3D9BindProgram(program); //Direct3D
cgGLBindProgram(program); // OpenGL cgD3D9BindProgram(program); //Direct3D
Releasing Resources 释放资源
- cgD3D9SetDevice(0);
- cgDestroyProgram(program);
- cgDestroyContext(context); //破坏所有
cgD3D9SetDevice(0); cgDestroyProgram(program); cgDestroyContext(context); //破坏所有
Cg Runtime 核心
顾名思义,应用中负责提供所有的Cg管理程序,主要负责3个主要概念:context,program,parameter,依次代表了CGcontext, CGprogram, 和CGparameter object 类型。
Cg Context 核心
向Cg runtime提供创造,毁灭,查询,链接等功能。
- CGcontext cgCreateContext(); //创造
- void cgDestroyContext(CGcontext context); //毁灭所有链接,包括包含此链接的所有程序
- CGbool cgIsContext(CGcontext context); //查询有效性
CGcontext cgCreateContext(); //创造 void cgDestroyContext(CGcontext context); //毁灭所有链接,包括包含此链接的所有程序 CGbool cgIsContext(CGcontext context); //查询有效性
Cg Program 核心
提供创建,毁灭,迭代结束,和查询程序。
- //程序直接包含源代码
- CGprogram cgCreateProgram(CGcontext context,CGenum programType,
- const char* program,CGprofile profile,
- const char* entry,const char** args);
- //一个字符串包含文件名,里面是源代码
- CGprogram cgCreateProgramFromFile(CGcontext context,CGenum programType,
- const char* program,CGprofile profile,
- const char* entry,const char** args);
- //移除程序
- void cgDestroyProgram(CGprogram program);
//程序直接包含源代码 CGprogram cgCreateProgram(CGcontext context,CGenum programType, const char* program,CGprofile profile, const char* entry,const char** args); //一个字符串包含文件名,里面是源代码 CGprogram cgCreateProgramFromFile(CGcontext context,CGenum programType, const char* program,CGprofile profile, const char* entry,const char** args); //移除程序 void cgDestroyProgram(CGprogram program);当一个程序问完成,他会自动卸载或者释放,为了方便下次使用,程序必须重编译再加载和回收。编译可执行手动执行或者自动:
- cgCompileProgram(CGprogram program); //一般用于编译或者重编译
- void cgSetAutoCompile(CGcontext ctx, CGenum flag);
- //后面的flag一般为CG_COMPILE_MANUAL、CG_COMPILE_IMMEDIATE、CG_COMPILE_LAZY
- CGbool cgIsProgramCompiled(CGprogram program);
cgCompileProgram(CGprogram program); //一般用于编译或者重编译 void cgSetAutoCompile(CGcontext ctx, CGenum flag); //后面的flag一般为CG_COMPILE_MANUAL、CG_COMPILE_IMMEDIATE、CG_COMPILE_LAZY CGbool cgIsProgramCompiled(CGprogram program);
程序包含链接,这里提供了迭代,如果没用返回0:
- CGprogram cgGetFirstProgram(CGcontext context);
- CGprogram cgGetNextProgram(CGprogram program);
- CGprogram program = cgGetFirstProgram(context);
- while (program != 0)
- {
- /* Here is the code that handles the program */
- program = cgGetNextProgram(program);
- }
CGprogram cgGetFirstProgram(CGcontext context); CGprogram cgGetNextProgram(CGprogram program); CGprogram program = cgGetFirstProgram(context); while (program != 0) { /* Here is the code that handles the program */ program = cgGetNextProgram(program); }
查询方法很多:
- CGbool cgIsProgram(CGprogram program); //有效性
- const char* cgGetLastListing(CGcontext context); //编译结果 只针对cgCreateProgram
- //得到属性
- CGcontext cgGetProgramContext(CGprogram program);
- CGprofile cgGetProgramProfile(CGprogram program);
- CGprofile cgGetProfile(const char* profileString);
- const char* cgGetProfileString(CGprofile profile);
- const char* cgGetProgramString(CGprogram program,
- CGenum stringType);
- //这里的stringType一般对应CG_PROGRAM_SOURCE、CG_PROGRAM_ENTRY、 CG_PROGRAM_PROFILE、CG_COMPILED_PROGRAM
CGbool cgIsProgram(CGprogram program); //有效性 const char* cgGetLastListing(CGcontext context); //编译结果 只针对cgCreateProgram //得到属性 CGcontext cgGetProgramContext(CGprogram program); CGprofile cgGetProgramProfile(CGprogram program); CGprofile cgGetProfile(const char* profileString); const char* cgGetProfileString(CGprofile profile); const char* cgGetProgramString(CGprogram program, CGenum stringType); //这里的stringType一般对应CG_PROGRAM_SOURCE、CG_PROGRAM_ENTRY、 CG_PROGRAM_PROFILE、CG_COMPILED_PROGRAM
Cg Parameters 核心
参数分为3类:程序参数、特效参数、共享参数。 分别联系着Cg programs,Cg Effects,Cg contexts。 Cg提供有提取,创建和查找程序参数。
- CGparameter cgGetFirstStructParameter(CGparameter parameter); //提供程序迭代,如果类型不为CG_STRUCT会返回0
CGparameter cgGetFirstStructParameter(CGparameter parameter); //提供程序迭代,如果类型不为CG_STRUCT会返回0同时要提供数组元素可使用:
- int cgGetArrayDimension(CGparameter parameter);
- int cgGetArraySize(CGparameter parameter, int dimension);
- CGparameter cgGetArrayParameter(CGparameter parameter,int index); //如果类型不为CG_ARRAY会返回0
int cgGetArrayDimension(CGparameter parameter); int cgGetArraySize(CGparameter parameter, int dimension); CGparameter cgGetArrayParameter(CGparameter parameter,int index); //如果类型不为CG_ARRAY会返回0下面是一个完整的使用实例:
- void IterateProgramParameters(CGprogram program)
- {
- RecurseProgramParameters(cgGetFirstParameter(program, CG_PROGRAM));
- }
- void RecurseProgramParameters(CGparameter parameter)
- {
- if (parameter == 0)
- return;
- do
- {
- switch(cgGetParameterType(parameter))
- {
- case CG_STRUCT:
- RecurseProgramParameters(
- cgGetFirstStructParameter(parameter));
- break;
- case CG_ARRAY:
- int arraySize = cgGetArraySize(parameter, 0);
- for (int i = 0; i < arraySize; ++i)
- RecurseProgramParameters(cgGetArrayParameter(parameter, i));
- break;
- default:
- /* Here is the code that handles the parameter */
- break;
- }
- } while((parameter = cgGetNextParameter(parameter))!= 0);
- }
void IterateProgramParameters(CGprogram program) { RecurseProgramParameters(cgGetFirstParameter(program, CG_PROGRAM)); } void RecurseProgramParameters(CGparameter parameter) { if (parameter == 0) return; do { switch(cgGetParameterType(parameter)) { case CG_STRUCT: RecurseProgramParameters( cgGetFirstStructParameter(parameter)); break; case CG_ARRAY: int arraySize = cgGetArraySize(parameter, 0); for (int i = 0; i < arraySize; ++i) RecurseProgramParameters(cgGetArrayParameter(parameter, i)); break; default: /* Here is the code that handles the parameter */ break; } } while((parameter = cgGetNextParameter(parameter))!= 0); }
实际上,经常遍历所有参数用“leaf”:
- CGparameter cgGetFirstLeafParameter(CGprogram program,CGenum namespace);
- CGparameter cgGetNextLeafParameter(CGparameter parameter);
CGparameter cgGetFirstLeafParameter(CGprogram program,CGenum namespace); CGparameter cgGetNextLeafParameter(CGparameter parameter);
所有程序参数可以直接寻回:
- CGparameter cgGetNamedProgramParameter(CGprogram program,CGenum namespace,const char* name);
CGparameter cgGetNamedProgramParameter(CGprogram program,CGenum namespace,const char* name);
Cg runtime提供的参数值管理方法:
- int cgGetParameterValue{i,f,d}{r,c}(CGparameter param, int nvals, type *v);
- const double* cgGetParameterValues(CGparameter parameter,CGenum valueType,int* numberOfValuesReturned);
int cgGetParameterValue{i,f,d}{r,c}(CGparameter param, int nvals, type *v); const double* cgGetParameterValues(CGparameter parameter,CGenum valueType,int* numberOfValuesReturned);
Shared Parameters 共享参数
Cgruntime支持创建任何类型的实例参数在一个Cg context中,一个参数可能连接多个拥有相同兼容的参数,包括任何程序或者环境参数在这个链接中。
共享参数通过CGcontext连接,创建方式如下:
- CGparameter cgCreateParameter(CGcontext ctx, CGtype type);
- CGparameter cgCreateParameterArray(CGtype type, int length);
- CGparameter cgCreateParameterMultiDimArray(CGtype type, int dim, int *lengths);
CGparameter cgCreateParameter(CGcontext ctx, CGtype type); CGparameter cgCreateParameterArray(CGtype type, int length); CGparameter cgCreateParameterMultiDimArray(CGtype type, int dim, int *lengths);删除方式:删除后所有连接取消
- Void cgDeleteParameter(CGparameter param);
Void cgDeleteParameter(CGparameter param);
连接参数:一个共享参数创建成功也许会连接很多程序,特效或者共享参数使用
- void cgConnectParamteer(CGparameter source, CGparameter sink);
- Void cgDisconnectParameter(param); //取消连接
void cgConnectParamteer(CGparameter source, CGparameter sink); Void cgDisconnectParameter(param); //取消连接
Cg中也经常使用模块或者是接口,这方面使用和普通高级语言类似。
Parameter Properties 参数属性
参数属性包含很多内容,含有效性、关联、大小、以及其他属性。
- interface MyInterface
- {
- float SomeMethod(float x);
- };
- struct MyStruct : MyInterface
- {
- float Scale;
- SomeMethod(float x)
- {
- return(Scale * x);
- }
- };
interface MyInterface { float SomeMethod(float x); }; struct MyStruct : MyInterface { float Scale; SomeMethod(float x) { return(Scale * x); } };
上面是一个例子,如果这个程序在开始时创建,那么MyInterface和MyStruct类型将会添加到输出结果中。下面是关联类型:
- CGtype cgGetParameterNamedType(CGparameter param);
- CGtype cgGetNamedUserType(CGhandle handle, const char *name); //handle可以使任意cg程序或者特效
- //父类可以获得所有入口点
- int cgGetNumParentTypes(CGtype type);
- CGtype cgGetParentType(CGtype type, int index);
- //单一类型获取入口点
- int cgGetNumUserTypes(CGprogram program);
- CGtype cgGetUserType(CGprogram program, int index);
- //针对老应用获取入口
- CGtype cgGetParameterType(CGparameter parameter);
- //可应用于查询
- const char* cgGetTypeString(CGtype type);
- //也可能是一般类型参数
- CGparameterclass cgGetParameterClass(CGparameter param);
CGtype cgGetParameterNamedType(CGparameter param); CGtype cgGetNamedUserType(CGhandle handle, const char *name); //handle可以使任意cg程序或者特效 //父类可以获得所有入口点 int cgGetNumParentTypes(CGtype type); CGtype cgGetParentType(CGtype type, int index); //单一类型获取入口点 int cgGetNumUserTypes(CGprogram program); CGtype cgGetUserType(CGprogram program, int index); //针对老应用获取入口 CGtype cgGetParameterType(CGparameter parameter); //可应用于查询 const char* cgGetTypeString(CGtype type); //也可能是一般类型参数 CGparameterclass cgGetParameterClass(CGparameter param);
同样可以查看有效性和关联性:
- CGbool cgIsParameter(CGparameter parameter);
- CGbool cgIsParameterReferenced(CGparameter parameter);
CGbool cgIsParameter(CGparameter parameter); CGbool cgIsParameterReferenced(CGparameter parameter);
查看大小:
- int cgGetParameterRows(CGparameter param);
- int cgGetParameterColumns(CGparameter param);
- int cgGetArrayDimension(CGparameter param); //维度
- int cgGetArraySize(CGparameter param, int dimension); //特定尺寸
- int cgGetArrayTotalSize(CGparameter param); //总共大小
- CGtype cgGetArrayType(CGparameter param); //规定类型可以在以后查询使用
- //一样可以用不固定类型数组
- void cgSetArraySize(CGparameter param, int size);
- void cgSetMultiDimArraySize(CGparameter param, int *sizes); //多维
int cgGetParameterRows(CGparameter param); int cgGetParameterColumns(CGparameter param); int cgGetArrayDimension(CGparameter param); //维度 int cgGetArraySize(CGparameter param, int dimension); //特定尺寸 int cgGetArrayTotalSize(CGparameter param); //总共大小 CGtype cgGetArrayType(CGparameter param); //规定类型可以在以后查询使用 //一样可以用不固定类型数组 void cgSetArraySize(CGparameter param, int size); void cgSetMultiDimArraySize(CGparameter param, int *sizes); //多维
查看属性
- CGparameterclass cgGetParameterClass(CGparameter param); //常规类查询
- /*
- CG_PARAMETERCLASS_SCALAR
- CG_PARAMETERCLASS_VECTOR
- CG_PARAMETERCLASS_MATRIX
- CG_PARAMETERCLASS_STRUCT
- CG_PARAMETERCLASS_SAMPLER
- CG_PARAMETERCLASS_OBJECT
- */
- //程序查询
- CGprogram cgGetParameterProgram(CGparameter parameter);
- //可变性查询
- CGenum cgGetParameterVariability(CGparameter parameter);
- //设置可变性,这里的vary可能为CG_UNIFORM,CG_LITERAL,CG_DEFAULT
- void cgSetParameterVariability(CGparameter parameter, CGenum vary);
- //获取参数方向
- CGenum cgGetParameterDirection(CGparameter parameter);
- //检索参数名
- const char* cgGetParameterName(CGparameter parameter);
- //取回语义字符串
- const char* cgGetParameterSemantic(CGparameter parameter);
- //资源分配参数,若没任何关联返回CG_UNDEFINED
- CGresource cgGetParameterResource(CGparameter parameter);
- //确定一个资源点和对应字符串
- CGresource cgGetResource(const char* resourceString);
- const char* cgGetResourceString(CGresource resource);
- //允许恢复原本资源
- CGresource cgGetParameterBaseResource(CGparameter parameter);
- //检索数值部分资源
- unsigned long cgGetParameterResourceIndex(CGparameter parameter);
- //得到默认或者统一数值
- const double* cgGetParameterValues(CGparameter parameter,CGenum valueType, int* numberOfValuesReturned);
CGparameterclass cgGetParameterClass(CGparameter param); //常规类查询 /* CG_PARAMETERCLASS_SCALAR CG_PARAMETERCLASS_VECTOR CG_PARAMETERCLASS_MATRIX CG_PARAMETERCLASS_STRUCT CG_PARAMETERCLASS_SAMPLER CG_PARAMETERCLASS_OBJECT */ //程序查询 CGprogram cgGetParameterProgram(CGparameter parameter); //可变性查询 CGenum cgGetParameterVariability(CGparameter parameter); //设置可变性,这里的vary可能为CG_UNIFORM,CG_LITERAL,CG_DEFAULT void cgSetParameterVariability(CGparameter parameter, CGenum vary); //获取参数方向 CGenum cgGetParameterDirection(CGparameter parameter); //检索参数名 const char* cgGetParameterName(CGparameter parameter); //取回语义字符串 const char* cgGetParameterSemantic(CGparameter parameter); //资源分配参数,若没任何关联返回CG_UNDEFINED CGresource cgGetParameterResource(CGparameter parameter); //确定一个资源点和对应字符串 CGresource cgGetResource(const char* resourceString); const char* cgGetResourceString(CGresource resource); //允许恢复原本资源 CGresource cgGetParameterBaseResource(CGparameter parameter); //检索数值部分资源 unsigned long cgGetParameterResourceIndex(CGparameter parameter); //得到默认或者统一数值 const double* cgGetParameterValues(CGparameter parameter,CGenum valueType, int* numberOfValuesReturned);
Cg核心错误报告
应用程序会缓冲查询错误代码,如下方法:
- CGerror error = cgGetError();
- CGerror error = cgGetFirstEror();
- const char* errorString = cgGetErrorString(error);
- //登记错误处理器
- typedef void (*CGerrorHandlerFunc)(CGcontext ctx, CGerror err, void *appdata);
- void cgSetErrorHandler(CGerrorHandlerFunc func, void *data);
CGerror error = cgGetError(); CGerror error = cgGetFirstEror(); const char* errorString = cgGetErrorString(error); //登记错误处理器 typedef void (*CGerrorHandlerFunc)(CGcontext ctx, CGerror err, void *appdata); void cgSetErrorHandler(CGerrorHandlerFunc func, void *data);
一般使用如下:
- void HandleCgError(CGcontext ctx, CGerror err, void *appdata)
- {
- fprintf(stderr, "Cg error: %s\n", cgGetErrorString(err));
- const char *listing = cgGetLastListing(ctx);
- if (listing != NULL)
- fprintf(stderr, " last listing: %s\n", listing);
- }
void HandleCgError(CGcontext ctx, CGerror err, void *appdata) { fprintf(stderr, "Cg error: %s\n", cgGetErrorString(err)); const char *listing = cgGetLastListing(ctx); if (listing != NULL) fprintf(stderr, " last listing: %s\n", listing); }
很多网友询问羽化如何使用Unity显示广告,看过源代码由于不难,用的是羽化写过的Android调用方法,没有深入研究,只是看到明哥实现过,所以先去明哥那取下经,在做研究- -
下期预告:
Unity Android平台AdMob应用