关于android:OpenGL ES 2.0/3.0 中的折射。大像素纹理

Refraction in OpenGL ES 2.0/3.0. Large pixels texture

尝试在 OpenGL ES 2.0/3.0 中实现折射。使用了以下着色器:

顶点着色器:

#version 300 es
precision lowp float;
uniform mat4 u_mvMatrix;

in vec4 a_position;  
in vec3 a_normal;
...
out mediump vec2 v_refractCoord;

const mediump float eta = 0.95;

void main() {
    vec4 eyePositionModel = u_mvMatrix * a_position;

    // eye direction in model space
    mediump vec3 eyeDirectModel = normalize(a_position.xyz - eyePositionModel.xyz);

    // calculate refraction direction in model space
    mediump vec3 refractDirect = refract(eyeDirectModel, a_normal, eta);

    // project refraction
    refractDirect = (u_mvpMatrix * vec4(refractDirect, 0.0)).xyw;

    // map refraction direction to 2d coordinates
    v_refractCoord = 0.5 * (refractDirect.xy / refractDirect.z) + 0.5;
    ...
}

片段着色器:

...
in mediump vec2 v_refractCoord;
uniform samplerCube s_texture; // skybox

void main() {
    outColor = texture(s_texture, vec3(v_refractCoord, 1.0));
}

纹理加载方法:

@JvmStatic
fun createTextureCubemap(context: Context, rowID: Int) {
    val input = context.resources.openRawResource(rowID)
    val bitmap = BitmapFactory.decodeStream(input)

    val textureId = IntArray(1)
    glGenTextures(1, textureId, 0)
    glBindTexture(GL_TEXTURE_CUBE_MAP, textureId[0])

    GLUtils.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, bitmap, 0)
    GLUtils.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, bitmap, 0)
    GLUtils.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, bitmap, 0)
    GLUtils.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, bitmap, 0)
    GLUtils.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, bitmap, 0)
    GLUtils.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, bitmap, 0)

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
    return textureId[0]
}

但是纹理是用大像素获得的,例如:

enter

这可能是什么原因?也许这对于低多边形模型来说是正常的?好像贴图太接近了。

注意:多边形越少 - 质量就越差。

提前感谢您的任何评论/回答!

图片来自 goodfon.ru

解决方案:根据@Rabbid76 的建议,我更改了正常数据。事实证明,在 Blender 中,您需要将对象的 Shading 设置为平滑(不平坦) - 这会在导出为 *.obj 格式时增加法线数量:为什么 OBJ 导出写入面法线而不是顶点法线

另外,根据@Rabbid76 的建议,我更改了以下内容:

vec3 eyeDirectModel = normalize(- eyePositionModel.xyz);

结果,像素化消失了:

enter

此外,在顶点着色器中计算折射时也可能出现像素伪影,因此我将计算转移到片段着色器中。这是修改后的着色器代码:

顶点着色器:

#version 300 es
precision lowp float;
uniform mat4 u_mvpMatrix;
uniform mat4 u_mvMatrix;

in vec4 a_position;
in vec3 a_normal;

out vec3 v_normal;
out lowp float SpecularIntensity;

out vec3 v_eyeDirectModel;

float getSpecularIntensity(vec4 position, vec3 a_normal, vec3 eyeDirectModel) {
    float shininess = 30.0;
    vec3 lightPosition = vec3(-20.0, 0.0, 0.0);
    mediump vec3 LightDirModel = normalize(lightPosition - position.xyz);
    mediump vec3 halfVector = normalize(LightDirModel + eyeDirectModel);
    lowp float NdotH = max(dot(a_normal, halfVector), 0.0);
    return pow(NdotH, shininess);
}

void main() {
    v_normal = a_normal;
    vec4 eyePositionModel = u_mvMatrix * a_position;
    // Eye direction in model space
    vec3 eyeDirectModel = normalize(- eyePositionModel.xyz);
    // specular lighting
    SpecularIntensity = getSpecularIntensity(a_position, a_normal, eyeDirectModel);
    v_eyeDirectModel = eyeDirectModel;
    gl_Position = u_mvpMatrix * a_position;
}

片段着色器:

#version 300 es
precision lowp float;
uniform mat4 u_mvpMatrix;

in vec3 v_normal;
in lowp float SpecularIntensity;
in vec3 v_eyeDirectModel;

out vec4 outColor;
uniform samplerCube s_texture; // skybox

const float eta = 0.65;
void main() {
    // Calculate refraction direction in model space
    vec3 refractDirect = refract(v_eyeDirectModel, normalize(v_normal), eta);
    // Project refraction
    refractDirect = (u_mvpMatrix * vec4(refractDirect, 0.0)).xyw;
    // Map refraction direction to 2d coordinates
    vec2 refractCoord = 0.5 * (refractDirect.xy / refractDirect.z) + 0.5;

    vec4 glassColor = texture(s_texture, vec3(refractCoord, 1.0));
    outColor = glassColor + SpecularIntensity;
    outColor.a = 0.8; // transparent
}

相关讨论

  • 将纹理缩小函数参数设置为 G_LLINEAR。参见 glTexParameterglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
  • @Rabbid76 感谢您对问题的关注!照你说的做了,并在答案中添加了代码。但这还没有帮助。一般来说,似乎像素大小对应多边形的大小,也许shader有错误?
  • 当 UV 坐标的整数部分变大时(例如 100.3 而不是 0.3),我在某些硬件上看到过类似的伪影。我还没有通过顶点着色器中的数学来确定这是否可能是问题所在,但我会首先尝试可视化 UV 以检查它们是否合理。
  • @Columbo 在 Blender 中进行 UV 展开 - 看起来不错,没有折射效果。还将计算转移到片段着色器,但问题仍然存在。不过谢谢你的建议!我会朝这个方向看。
  • @alexrnov您是计算每个顶点的法线向量还是使用面法线向量?
  • @Rabbid76 对不起,但我不知道)))。法线数据取自 *.obj 文件(来自 Blender),格式为:vn 0.5416 -0.3089 0.7818。着色器代码部分取自 PVRShamanGUI。那里的图片很好。

首先在着色器代码中有一个错误。 a_position.xyz - eyePositionModel.xyz 没有任何意义,因为 a_position 是模型空间中的顶点坐标,而 eyePositionModel 是视图空间中的顶点坐标。
您必须在视图空间中计算 refract 的事件向量。那是从眼睛位置到顶点的向量。由于眼睛在视图空间中的位置是 (0, 0, 0),所以它是:

vec4 eyePositionView = u_mvMatrix * a_position;

// eye direction in model space
mediump vec3 eyeDirectView = normalize(- eyePositionView.xyz);

此外,这是一个法线向量属性的问题。
问题是由于法向量是按面计算的,而不是针对每个顶点单独计算的。
注意,折射方向(refractDirect)取决于顶点坐标(eyeDirectModel)和法向量(a_normal):

mediump vec3 refractDirect = refract(eyeDirectModel, a_normal, eta);

由于相邻曲面之间的法线向量不同,您可以在网格面之间看到明显的边缘。

enter

相关讨论

  • 您能否告诉我是否需要更改法线数据或更改着色器代码?
  • @alexrnov 着色器是正确的。如答案中所述,法线向量似乎是面法线向量。这是法线向量属性而不是着色器的问题。
  • 非常感谢你!!!我将更改普通属性的数据。
  • 太棒了!甚至使用一个: normalize(- eyePositionView.xyz) 现在使图像好多了!

以上是关于android:OpenGL ES 2.0/3.0 中的折射。大像素纹理的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>