保持应该表示相同功能的同步 glsl 代码和 C++ 代码
Keeping synced glsl code and c++ code that ought to represent the same function
我有以下挑战。我正在做一系列图形实验,我需要编写 sdf 函数。为了不同的目的,这些函数必须同时存在于 glsl 和 c++ 中。换句话说,在 glsl 和 c++ 中,必须有一个函数 SdfFunction
计算完全相同的 SDF。
当前可能的方法:
- 手动编写函数两次。这个超级慢而且很容易出错。
- 制作一个必须 运行 将 glsl 代码转换为 C++ 的解析器脚本,反之亦然。这只在构建时工作并且需要额外的编程语言(以使其可移植)。
- 让 C++ 代码本身解析文件。然后在运行时编译一个动态加载的库和link到生成的文件。我不知道该怎么做,听起来很乱。
我有其他选择吗?
我使用的方法有点不同。我为 CPU 侧 C++ 代码创建了 GLSL_math.h 模板,其语法和功能与 GLSL 相同(包括调配),因此我可以 运行 GLSL 上的相同数学代码和 CPU调试目的。该模板还包含原生 GLSL 中不存在的局部和全局旋转(因为我打算用它来替代我的旧 reper 和矢量数学 类 并且需要该功能)
该模板是在 Embarcadero (Borland) BDS2006 Turbo C++ 中完成的,因此可能需要在不同的 C++ IDE / 编译器中进行一些调整。大多数代码是使用函数 _vec_generate
自动生成的,该函数包含在内但被注释掉,因为它使用 AnsiString,它在 VCL 之外不存在,因为手动编码会很疯狂(~244KByte)。
CPU/GLSL 之间的纹理访问和内容差异我通过宏语句处理,如下所示:
只有 GLSL 和 CPU 的宏不同...
这样我就可以使用我的 C++ IDE 调试功能,例如断点、跟踪、监视...没有这些功能,我将永远无法完成更复杂的着色器,例如通过网格或体素贴图的光线跟踪器...
对于行为不同的情况(不同的 FPU 实现或与驱动程序相关的 GLSL 怪癖和错误)我使用这个:
直接从片段着色器打印出sub-results
这里是一个示例测试代码,用于测试模板运算符语法的功能(不同的编译器可能需要稍微更改运算符 header 语法,直到它编译):
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
template <class mat,class vec,class T> void test_operators_syntax()
{
mat m0,m1,m2;
vec v0,v1,v2;
T c1=1;
m0=+m1;
m0=-m1;
m0=m1*m2;
m0=c1*m1;
m0=m1*c1;
m0=m1/c1;
m0*=m1;
m0*=c1;
m0/=c1;
v0=m1*v1;
v0=m1*v1;
v0=m1*v1;
v0=+v1;
v0=-v1;
v0=v1++;
v0=++v1;
v0=v1--;
v0=--v1;
v0=v1+v2;
v0=v1-v2;
v0=v1*v2;
v0=v1/v2;
v0+=v1;
v0-=v1;
v0*=v1;
v0/=v1;
v0++=v1;
v0--=v1;
v0=c1+v1;
v0=c1-v1;
v0=c1*v1;
v0=v1+c1;
v0=v1-c1;
v0=v1*c1;
v0=v1/c1;
v0+=c1;
v0-=c1;
v0*=c1;
v0/=c1;
};
//---------------------------------------------------------------------------
void test_operators()
{
test_operators_syntax< mat2, vec2,float >(); vec2 v2= vec2(0.0,0.0); mat2 m2= mat2(0.0,0.0,0.0,0.0);
test_operators_syntax< mat3, vec3,float >(); vec3 v3= vec3(0.0,0.0,0.0); mat3 m3= mat3(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
test_operators_syntax< mat4, vec4,float >(); vec4 v4= vec4(0.0,0.0,0.0,0.0); mat4 m4= mat4(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
test_operators_syntax<dmat2,dvec2,double>(); dvec2 dv2=dvec2(0.0,0.0); dmat2 dm2=dmat2(0.0,0.0,0.0,0.0);
test_operators_syntax<dmat3,dvec3,double>(); dvec3 dv3=dvec3(0.0,0.0,0.0); dmat3 dm3=dmat3(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
test_operators_syntax<dmat4,dvec4,double>(); dvec4 dv4=dvec4(0.0,0.0,0.0,0.0); dmat4 dm4=dmat4(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
m3=rotate(m3,15.0*deg,v2);
m4=rotate(m4,15.0*deg,v3,v3);
m3=grotz(m3,15.0*deg); m3=lrotz(m3,15.0*deg);
m4=grotx(m4,15.0*deg); m4=lrotx(m4,15.0*deg);
m4=groty(m4,15.0*deg); m4=lroty(m4,15.0*deg);
m4=grotz(m4,15.0*deg); m4=lrotz(m4,15.0*deg);
m2=inverse(m2); m2=inverse2(m2); m2=transpose(m2);
m3=inverse(m3); m3=inverse2(m3); m3=transpose(m3);
m4=inverse(m4); m4=inverse2(m4); m4=transpose(m4);
float f=1.0; f=max(0.0f,f); f=min(0.0f,f); f=abs(f);
double d=2.0; d=max(0.0 ,d); d=min(0.0 ,d); d=abs(d);
f=length(v2)+length2(v2)+dot(normalize(v2),cross(v2));
f=length(v3)+length2(v3)+dot(normalize(v3),cross(v3,v3));
f=length(v4)+length2(v4)+dot(normalize(v4),cross(v4,v4,v4));
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
我有以下挑战。我正在做一系列图形实验,我需要编写 sdf 函数。为了不同的目的,这些函数必须同时存在于 glsl 和 c++ 中。换句话说,在 glsl 和 c++ 中,必须有一个函数 SdfFunction
计算完全相同的 SDF。
当前可能的方法:
- 手动编写函数两次。这个超级慢而且很容易出错。
- 制作一个必须 运行 将 glsl 代码转换为 C++ 的解析器脚本,反之亦然。这只在构建时工作并且需要额外的编程语言(以使其可移植)。
- 让 C++ 代码本身解析文件。然后在运行时编译一个动态加载的库和link到生成的文件。我不知道该怎么做,听起来很乱。
我有其他选择吗?
我使用的方法有点不同。我为 CPU 侧 C++ 代码创建了 GLSL_math.h 模板,其语法和功能与 GLSL 相同(包括调配),因此我可以 运行 GLSL 上的相同数学代码和 CPU调试目的。该模板还包含原生 GLSL 中不存在的局部和全局旋转(因为我打算用它来替代我的旧 reper 和矢量数学 类 并且需要该功能)
该模板是在 Embarcadero (Borland) BDS2006 Turbo C++ 中完成的,因此可能需要在不同的 C++ IDE / 编译器中进行一些调整。大多数代码是使用函数 _vec_generate
自动生成的,该函数包含在内但被注释掉,因为它使用 AnsiString,它在 VCL 之外不存在,因为手动编码会很疯狂(~244KByte)。
CPU/GLSL 之间的纹理访问和内容差异我通过宏语句处理,如下所示:
只有 GLSL 和 CPU 的宏不同...
这样我就可以使用我的 C++ IDE 调试功能,例如断点、跟踪、监视...没有这些功能,我将永远无法完成更复杂的着色器,例如通过网格或体素贴图的光线跟踪器...
对于行为不同的情况(不同的 FPU 实现或与驱动程序相关的 GLSL 怪癖和错误)我使用这个:
直接从片段着色器打印出sub-results
这里是一个示例测试代码,用于测试模板运算符语法的功能(不同的编译器可能需要稍微更改运算符 header 语法,直到它编译):
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
template <class mat,class vec,class T> void test_operators_syntax()
{
mat m0,m1,m2;
vec v0,v1,v2;
T c1=1;
m0=+m1;
m0=-m1;
m0=m1*m2;
m0=c1*m1;
m0=m1*c1;
m0=m1/c1;
m0*=m1;
m0*=c1;
m0/=c1;
v0=m1*v1;
v0=m1*v1;
v0=m1*v1;
v0=+v1;
v0=-v1;
v0=v1++;
v0=++v1;
v0=v1--;
v0=--v1;
v0=v1+v2;
v0=v1-v2;
v0=v1*v2;
v0=v1/v2;
v0+=v1;
v0-=v1;
v0*=v1;
v0/=v1;
v0++=v1;
v0--=v1;
v0=c1+v1;
v0=c1-v1;
v0=c1*v1;
v0=v1+c1;
v0=v1-c1;
v0=v1*c1;
v0=v1/c1;
v0+=c1;
v0-=c1;
v0*=c1;
v0/=c1;
};
//---------------------------------------------------------------------------
void test_operators()
{
test_operators_syntax< mat2, vec2,float >(); vec2 v2= vec2(0.0,0.0); mat2 m2= mat2(0.0,0.0,0.0,0.0);
test_operators_syntax< mat3, vec3,float >(); vec3 v3= vec3(0.0,0.0,0.0); mat3 m3= mat3(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
test_operators_syntax< mat4, vec4,float >(); vec4 v4= vec4(0.0,0.0,0.0,0.0); mat4 m4= mat4(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
test_operators_syntax<dmat2,dvec2,double>(); dvec2 dv2=dvec2(0.0,0.0); dmat2 dm2=dmat2(0.0,0.0,0.0,0.0);
test_operators_syntax<dmat3,dvec3,double>(); dvec3 dv3=dvec3(0.0,0.0,0.0); dmat3 dm3=dmat3(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
test_operators_syntax<dmat4,dvec4,double>(); dvec4 dv4=dvec4(0.0,0.0,0.0,0.0); dmat4 dm4=dmat4(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
m3=rotate(m3,15.0*deg,v2);
m4=rotate(m4,15.0*deg,v3,v3);
m3=grotz(m3,15.0*deg); m3=lrotz(m3,15.0*deg);
m4=grotx(m4,15.0*deg); m4=lrotx(m4,15.0*deg);
m4=groty(m4,15.0*deg); m4=lroty(m4,15.0*deg);
m4=grotz(m4,15.0*deg); m4=lrotz(m4,15.0*deg);
m2=inverse(m2); m2=inverse2(m2); m2=transpose(m2);
m3=inverse(m3); m3=inverse2(m3); m3=transpose(m3);
m4=inverse(m4); m4=inverse2(m4); m4=transpose(m4);
float f=1.0; f=max(0.0f,f); f=min(0.0f,f); f=abs(f);
double d=2.0; d=max(0.0 ,d); d=min(0.0 ,d); d=abs(d);
f=length(v2)+length2(v2)+dot(normalize(v2),cross(v2));
f=length(v3)+length2(v3)+dot(normalize(v3),cross(v3,v3));
f=length(v4)+length2(v4)+dot(normalize(v4),cross(v4,v4,v4));
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------