在网上一搜画球能搜出大片方法,大概原理都是把求分为很多个三角形然后画出来.这段时间有空想起以前看过的shadertoy.com这个网站,一时兴起想能不能只用shader来画一个?实践了下发现代码还挺简单:
vertex Shader:
precision mediump float;
attribute vec3 position;
attribute vec2 texCoord;
uniform mat4 ModelViewMatrix;
uniform mat4 ProjectionMatrix;
mat4 u_modelViewProjectionMatrix;
varying mediump vec2 v_texCoord;
void main()
{
u_modelViewProjectionMatrix = ProjectionMatrix * ModelViewMatrix;
v_texCoord = texCoord;
gl_Position = u_modelViewProjectionMatrix * vec4(position, 1.);
}
其中 u_modelViewProjectionMatrix 是单位矩阵.
然后是fragmentshader:
precision mediump float;
uniform lowp sampler2D mytexture; //u_Sampler
uniform float u_Scale, u_Aspect;
uniform mat3 u_Transform;
uniform mat4 u_Proj;
varying mediump vec2 v_texCoord;
#define PI 3.141592653589793
void main()
{
vec2 rads = vec2(PI * 2., PI);
vec2 uv = (v_texCoord.xy ) * 2.0 - 1.0; //-1.0 ~ 1.0
uv.y *= u_Aspect; // adjust for aspect
float rr = dot(uv, uv);
float t = abs(1.0 - rr); //球半径为1.0
float z = sqrt(t); //该点在球上的z值.
z= -1.0 *z;
vec3 sphere_pnt = vec3(uv.x,uv.y,z);
float lon = atan(sphere_pnt.z,sphere_pnt.x);
float lat = acos(sphere_pnt.y);
vec2 norCoord = vec2(lon, lat) / rads;
norCoord.x = 1.0 - norCoord.x;
gl_FragColor = texture2D(mytexture, norCoord);
}
基本原理就是以屏幕位置作为一个半径为1的球的x y坐标.算出z值,得到球表面的三维坐标,再转为极坐标系,在纹理图中找到对应位置.得到最终效果:
最终效果离我的理想效果有点差距. 代码中我的z值取负数,理论上贴出来的应该是球背面,也就是像上次写的这篇文章的效果OpenGL,z值转深度值计算 - 拖延症补丁.exe - 博客频道 - youkuaiyun.com .把z>0的称为前半球,z<0的称为后半球.实际上把z改为正数发现纹理采样确实采到后面去了.但是依然是凸起的效果.也就是始终沿着前半球表面采样.
想了好久,请教了大神也没解决, 先放博客搁置了.
我猜可能和投影矩阵有关.这样变换的程序确定是无法设置projectMatrix,也就是使用的是indentify matrix. 因为projectMatrix可能不是正定的,也没办法取逆来做.带进一步检验.