我正在尝试对球体进行纹理处理。我的顶点着色器:
attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec3 a_texCoord0;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform sampler2D u_texture;
varying vec3 fragPos;
varying vec3 normal;
varying vec3 color;
void main()
{
gl_Position = projection * view * model * vec4(a_position, 1.0);
fragPos = vec3(model * vec4(a_position, 1.0));
normal = a_normal;
if(a_texCoord0.x > 50){
color = vec3(1f, 0.0f, 0.0f);
} else {
color = texture(u_texture, a_texCoord0);
}
}
我的片段着色器:
#ifdef GL_ES
precision mediump float;
#endif
varying vec3 normal;
varying vec3 color;
varying vec3 fragPos;
uniform vec3 lightPos;
uniform vec3 lightColor;
void main()
{
// Ambient
float ambientStrength = 0.1;
vec3 ambient = ambientStrength * lightColor;
// Diffuse
vec3 norm = normalize(normal);
vec3 lightDir = normalize(lightPos - fragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
//vec3 result = (ambient + diffuse) * color;
vec3 result = color;
gl_FragColor = vec4(result, 1.0);
}
我用二十面体构建球体,但使用6种相同的纹理对其进行纹理化,然后通过cubemap principe将其连接起来。这就是我将球坐标转换为UV的代码:
public void fillTexInformation(Vertex vertex){
float[] sphericalCoord = GeometryHelper.toSphericalCoordinates(vertex.getPosition());
vertex.setTexCoord(projection(sphericalCoord[1], sphericalCoord[2]));
}
/**
* Project point on shpere to texture coordinate
* @param theta
* @param phi
* @return
*/
//https://stackoverflow.com/questions/29678510/convert-21-equirectangular-panorama-to-cube-map
private Vector2 projection(float theta, float phi) {
if (theta < 0.615) {
return projectRight(theta, phi);
} else if (theta > 2.527) {
return projectLeft(theta, phi);
} else if (phi <= Math.PI / 4 || phi > 7 * Math.PI / 4) {
return projectBack(theta, phi);
} else if (phi > Math.PI / 4 && phi <= 3 * Math.PI / 4) {
return projectBottom(theta, phi);
} else if (phi >3 * Math.PI / 4 && phi <= 5 * Math.PI / 4) {
return projectFront(theta, phi);
} else if (phi > 5 * Math.PI / 4 && phi <= 7 * Math.PI / 4) {
return projectTop(theta, phi);
} else {
throw new RuntimeException("Algorithm error");
}
}
private Vector2 projectBack(float theta, float phi) {
float y = (float) Math.tan(phi);
float z = (float) ((1 / Math.tan(theta)) / Math.cos(phi));
if (z < -1) {
return projectLeft(theta, phi);
}
if (z > 1) {
return projectRight(theta, phi);
}
return new Vector2(normilizeTexCoord(y), normilizeTexCoord(z));
}
private Vector2 projectBottom(float theta, float phi) {
float x = (float) Math.tan(phi - Math.PI / 2);
float z = (float) ((1 / Math.tan(theta)) / Math.cos(phi - Math.PI / 2));
if (z < -1) {
return projectLeft(theta, phi);
}
if (z > 1) {
return projectRight(theta, phi);
}
// return new Vector2(normilizeTexCoord(x), normilizeTexCoord(z));
return new Vector2(100, 100);
}
private Vector2 projectFront(float theta, float phi) {
float y = (float) Math.tan(phi);
float z = (float) (-(1 / Math.tan(theta)) / Math.cos(phi));
if (z < -1) {
return projectLeft(theta, phi);
}
if (z > 1) {
return projectRight(theta, phi);
}
// return new Vector2(normilizeTexCoord(y), normilizeTexCoord(z));
return new Vector2(100, 100);
}
private Vector2 projectTop(float theta, float phi) {
float x = (float) Math.tan(phi - 3 * Math.PI / 2);
float z = (float) ((1 / Math.tan(theta)) / Math.cos(phi - 3 * Math.PI / 2));
if (z < -1) {
return projectLeft(theta, phi);
}
if (z > 1) {
return projectRight(theta, phi);
}
// return new Vector2(normilizeTexCoord(x), normilizeTexCoord(z));
return new Vector2(100, 100);
}
private Vector2 projectRight(float theta, float phi) {
float x = (float) (Math.tan(theta) * Math.cos(phi));
float y = (float) (Math.tan(theta) * Math.sin(phi));
// return new Vector2(normilizeTexCoord(x), normilizeTexCoord(y));
return new Vector2(100, 100);
}
private Vector2 projectLeft(float theta, float phi) {
float x = (float) (-Math.tan(theta) * Math.cos(phi));
float y = (float) (-Math.tan(theta) * Math.sin(phi));
// return new Vector2(normilizeTexCoord(x), normilizeTexCoord(-y));
return new Vector2(100, 100);
}
private float normilizeTexCoord(float coord){
return (coord + 1) / 2;
}
结果,我得到的纹理质量非常糟糕。这是original texture和what I get on sphere(这里只是立方体贴图的一部分,另一面是红色的)。 我猜想它可能与构建方法(来自二十面体)和纹理化(具有某种立方体贴图)的差异有关。但这可以解释质地不均匀的边缘,但质量损失却不那么可怕。有人可以告诉我这里会发生什么吗?
答案 0 :(得分:4)
之所以发生这种情况,是因为您在顶点着色器中对纹理进行了采样,这意味着每个三角形的角只会得到三种颜色。其他像素将被插值。
为获得更好的质量,应将纹理采样移至片段着色器,并插入uv坐标而不是颜色:
顶点着色器:
attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec3 a_texCoord0;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
varying vec3 fragPos;
varying vec3 normal;
varying vec2 texcoord0;
void main()
{
gl_Position = projection * view * model * vec4(a_position, 1.0);
fragPos = vec3(model * vec4(a_position, 1.0));
normal = a_normal;
texcoord0 = a_texCoord0;
}
片段着色器:
varying vec3 normal;
varying vec2 texcoord0;
varying vec3 fragPos;
uniform sampler2D u_texture;
uniform vec3 lightPos;
uniform vec3 lightColor;
void main()
{
vec3 color = texture(u_texture, texcoord0).rgb;
// Ambient
float ambientStrength = 0.1;
vec3 ambient = ambientStrength * lightColor;
// Diffuse
vec3 norm = normalize(normal);
vec3 lightDir = normalize(lightPos - fragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
//vec3 result = (ambient + diffuse) * color;
vec3 result = color;
gl_FragColor = vec4(result, 1.0);
}