我在Processing(Java)中编写了一个简单的Sphere Tracer,并将其移植到WebGL / GLSL。当我在Processing中编写它时,我有一个基类Shape
,并将其扩展为特定的形状,如Box
,Plane
,Sphere
等。每个特定的形状都有成员与它相关的,例如Sphere
个实例有一个半径,Box
个实例有一个长度向量,等等。另外,每个实例都有一个特定于形状的距离函数。
不幸的是我不能在GLSL中使用这样的类,因此我创建了一个可以表示任何形状的struct
(我在下面将其称为Object
):
struct Object {
vec3 pos, len, nDir;
float rad;
} objects[4];
然后我为每种形状写了一个距离函数:
float boxSignedDist(Object inBox, vec3 inPos) {
vec3 boxDelta = abs(inPos-inBox.pos)-inBox.len;
return min(max(boxDelta.x, max(boxDelta.y, boxDelta.z)), 0.0)+length(max(boxDelta, 0.0));
}
float planeSignedDist(Object inPlane, vec3 inPos) {
return dot(inPos-inPlane.pos, inPlane.nDir);
}
float roundBoxUnsignedDist(Object inRoundBox, vec3 inPos) {
return length(max(abs(inPos-inRoundBox.pos)-inRoundBox.len, 0.0))-inRoundBox.rad;
}
float sphereSignedDist(Object inSphere, vec3 inPos) {
return length(inPos-inSphere.pos)-inSphere.rad;
}
现在我遇到了一个不同的问题,即用另一个函数(如旋转)包裹形状特定的距离函数,如何在GLSL中有效地完成这一操作并不明显。我添加了一个成员到Object
,int type
,然后为我支持的每个形状做了几个#define
:
#define BOX_SIGNED 1
#define PLANE_SIGNED 2
#define ROUNDBOX_UNSIGNED 3
#define SPHERE_SIGNED 4
struct Object {
int type;
vec3 pos, len, nDir;
float rad;
} objects[4];
现在我可以将旋转包装器编写为这样的距离函数:
float rotateY(Object inObject, vec3 inPos, float inRadians) {
inPos -= inObject.pos;
inObject.pos = vec3(0.0, 0.0, 0.0);
float cRad = cos(inRadians);
float sRad = sin(inRadians);
if (inObject.type == BOX_SIGNED)
return boxSignedDist(inObject, vec3(cRad*inPos.x-sRad*inPos.z, inPos.y, cRad*inPos.z+sRad*inPos.x));
else if (inObject.type == PLANE_SIGNED)
return planeSignedDist(inObject, vec3(cRad*inPos.x-sRad*inPos.z, inPos.y, cRad*inPos.z+sRad*inPos.x));
else if (inObject.type == ROUNDBOX_UNSIGNED)
return roundBoxUnsignedDist(inObject, vec3(cRad*inPos.x-sRad*inPos.z, inPos.y, cRad*inPos.z+sRad*inPos.x));
else if (inObject.type == SPHERE_SIGNED)
return sphereSignedDist(inObject, vec3(cRad*inPos.x-sRad*inPos.z, inPos.y, cRad*inPos.z+sRad*inPos.x));
else
return 0.0;
}
看来这是必要的,有没有更好的方法呢?如果rotateY
能够接收一个函数指针来调用适当的函数而不是全部else if
答案 0 :(得分:8)
GLSL确实是一种非常有限的语言。编译器在优化某些事情方面做得很好,但并不完美。
要记住的一些事情:
int[4]
数组与vec4[4]
数组具有相同的内存。您的Object
应将vec3
与float
s。if (type == ...
来改进inPos
代码,但我无法看到if语句的方法。也许您可以为每种对象类型(或使用宏)编写函数的排列并分别跟踪批量类型?你可能会看到一些好主意,看看人们为https://www.shadertoy.com/所写的内容。
最后,GLSL 子例程具有与函数指针类似的意图,但在全局范围内用于所有着色器执行,并且在此处不会提供帮助。