我正在使用 OpenGL ES 2 和两个设备为 Android 开发:Google Nexus 3 和 Archos 80 G9(8" 平板电脑)。在这些设备上,我的着色器工作正常。
现在,我购买了三星 Galaxy Tab 2,但单个顶点着色器无法在此设备上运行。这个着色器(来自 OSGEarth)消除了 3D 地形上轨道的 z-fighting 问题,调制顶点的 z 值。在三星 Galaxy Tab 2 上,此调制不起作用(!)
这是着色器
std::string vertexShaderSource =
"#version 100\n\n"
"float remap( float val, float vmin, float vmax, float r0, float r1 ) \n"
"{ \n"
" float vr = (clamp(val, vmin, vmax)-vmin)/(vmax-vmin); \n"
" return r0 + vr * (r1-r0); \n"
"} \n\n"
"mat3 castMat4ToMat3Function(in mat4 m) \n"
"{ \n"
" return mat3( m[0].xyz, m[1].xyz, m[2].xyz ); \n"
"} \n\n"
"uniform mat4 osg_ViewMatrix; \n"
"uniform mat4 osg_ViewMatrixInverse; \n"
"uniform mat4 osg_ModelViewMatrix; \n"
"uniform mat4 osg_ProjectionMatrix; \n"
"uniform mat4 osg_ModelViewProjectionMatrix; \n"
"uniform float osgearth_depthoffset_minoffset; \n"
"attribute vec4 osg_Vertex;\n"
"attribute vec4 osg_Color;\n"
"varying vec4 v_color; \n\n"
"varying vec4 adjV; \n"
"varying float simRange; \n\n"
"void main(void) \n"
"{ \n"
// transform the vertex into eye space:
" vec4 vertEye = osg_ModelViewMatrix * osg_Vertex; \n"
" vec3 vertEye3 = vertEye.xyz/vertEye.w; \n"
" float range = length(vertEye3); \n"
// vec3 adjVecEye3 = normalize(vertEye3); \n"
// calculate the "up" vector, that will be our adjustment vector:
" vec4 vertWorld = osg_ViewMatrixInverse * vertEye; \n"
" vec3 adjVecWorld3 = -normalize(vertWorld.xyz/vertWorld.w); \n"
" vec3 adjVecEye3 = castMat4ToMat3Function(osg_ViewMatrix) * adjVecWorld3; \n"
// remap depth offset based on camera distance to vertex. The farther you are away,
// the more of an offset you need.
" float offset = remap( range, 1000.0, 10000000.0, osgearth_depthoffset_minoffset, 10000.0); \n"
// adjust the Z (distance from the eye) by our offset value:
" vertEye3 -= adjVecEye3 * offset; \n"
" vertEye.xyz = vertEye3 * vertEye.w; \n"
// Transform the new adjusted vertex into clip space and pass it to the fragment shader.
" adjV = osg_ProjectionMatrix * vertEye; \n"
// Also pass along the simulated range (eye=>vertex distance). We will need this
// to detect when the depth offset has pushed the Z value "behind" the camera.
" simRange = range - offset; \n"
" gl_Position = osg_ModelViewProjectionMatrix * osg_Vertex; \n"
" v_color = osg_Color; \n"
// transform clipspace depth into [0..1] for FragDepth:
" gl_Position.z = max(0.0, (adjV.z/adjV.w)*gl_Position.w ); \n"
// if the offset pushed the Z behind the eye, the projection mapping will
// result in a z>1. We need to bring these values back down to the
// near clip plan (z=0). We need to check simRange too before doing this
// so we don't draw fragments that are legitimently beyond the far clip plane.
" float z = 0.5 * (1.0+(adjV.z/adjV.w)); \n"
" if ( z > 1.0 && simRange < 0.0 ) { gl_Position.z = 0.0; } \n"
"} \n" ;
使用此代码,地形上的轨迹根本不会在 SGT2 上显示。如果注释指令
gl_Position.z = max(0.0, (adjV.z/adjV.w)*gl_Position.w );
着色器工作,并显示轨道,但当然 z-figthing 没有被删除。
我的 Google Nexus 和三星 Galaxy Tab 2 都使用 PowerVR SGX 540,所以问题可能出在不同 CPU 的浮点数学精度上?(或者一些错误?)
有任何想法吗?
谢谢
[已解决] 我从顶点着色器中删除
"varying vec4 adjV; \n"
"varying float simRange; \n\n"
并将它们声明为 ad vec4/float。我认为他们将 mediump 精度分配为变量。