如何使用立方体贴图对非展开模型进行贴图

时间:2019-04-29 05:01:38

标签: opengl-es libgdx glsl opengl-es-2.0

我有很多无法展开的模型(它们没有UV坐标)。解开它们非常复杂。因此,我决定使用无缝立方体贴图对其进行纹理处理:

[VERT]

attribute vec4 a_position;

varying vec3 texCoord;

uniform mat4 u_worldTrans;
uniform mat4 u_projTrans;
...

void main()
{
   gl_Position = u_projTrans * u_worldTrans * a_position;
   texCoord = vec3(a_position);
} 


[FRAG]
varying vec3 texCoord;
uniform samplerCube u_cubemapTex;

void main()
{
  gl_FragColor = textureCube(u_cubemapTex, texCoord);
}

它可以工作,但是由于纹理取决于顶点位置,因此结果很奇怪。如果我的模型比立方体或球体更复杂,我会在对象的某些部分看到可见的接缝和纹理的低分辨率。

反射在模型上映射良好,但具有镜面效果。

反射:

[VERT]
attribute vec3 a_normal;

varying vec3 v_reflection;

uniform mat4 u_matViewInverseTranspose;
uniform vec3 u_cameraPos;
...

void main()
{
   mat3 normalMatrix = mat3(u_matViewInverseTranspose);
   vec3 n = normalize(normalMatrix * a_normal);

   //calculate reflection
   vec3 vView = a_position.xyz - u_cameraPos.xyz;
   v_reflection = reflect(vView, n);

   ...
}

如何实现类似反射的效果,但具有“粘性”效果,这意味着纹理好像附着在某个顶点上(不移动)。模型的每一侧都必须显示自己的立方体贴图一侧,因此,它应该看起来像是普通的2D纹理。任何建议将不胜感激。

更新1

我总结了所有评论,并决定计算立方体贴图UV。由于我使用LibGDX,因此某些名称可能与OpenGL有所不同。

着色器类:

public class CubemapUVShader implements com.badlogic.gdx.graphics.g3d.Shader {
  ShaderProgram program;
  Camera camera;
  RenderContext context;

  Matrix4 viewInvTraMatrix, viewInv;

  Texture texture;
  Cubemap cubemapTex;

  ...

  @Override
  public void begin(Camera camera, RenderContext context) {
    this.camera = camera;
    this.context = context;
    program.begin();

    program.setUniformMatrix("u_matProj", camera.projection);
    program.setUniformMatrix("u_matView", camera.view);

    cubemapTex.bind(1);
    program.setUniformi("u_textureCubemap", 1);

    texture.bind(0);
    program.setUniformi("u_texture", 0);

    context.setDepthTest(GL20.GL_LEQUAL);       
    context.setCullFace(GL20.GL_BACK);
  }

  @Override
  public void render(Renderable renderable) {
    program.setUniformMatrix("u_matModel", renderable.worldTransform);
    viewInvTraMatrix.set(camera.view);
    viewInvTraMatrix.mul(renderable.worldTransform);
    program.setUniformMatrix("u_matModelView", viewInvTraMatrix);
    viewInvTraMatrix.inv();
    viewInvTraMatrix.tra();
    program.setUniformMatrix("u_matViewInverseTranspose", viewInvTraMatrix);

    renderable.meshPart.render(program);
  }     
...
}

顶点:

attribute vec4 a_position;
attribute vec2 a_texCoord0;
attribute vec3 a_normal;
attribute vec3 a_tangent;
attribute vec3 a_binormal;

varying vec2 v_texCoord;
varying vec3 v_cubeMapUV;

uniform mat4 u_matProj;
uniform mat4 u_matView;
uniform mat4 u_matModel;

uniform mat4 u_matViewInverseTranspose;
uniform mat4 u_matModelView;


void main()
{   
    gl_Position = u_matProj * u_matView * u_matModel * a_position;
    v_texCoord = a_texCoord0;       

    //CALCULATE CUBEMAP UV (WRONG!)
    //I decided that tm_l2g mentioned in comments is u_matView * u_matModel
    v_cubeMapUV = vec3(u_matView * u_matModel * vec4(a_normal, 0.0));

    /*
    mat3 normalMatrix = mat3(u_matViewInverseTranspose);

    vec3 t = normalize(normalMatrix * a_tangent);
    vec3 b = normalize(normalMatrix * a_binormal);
    vec3 n = normalize(normalMatrix * a_normal);    
    */
}

片段:

varying vec2 v_texCoord;
varying vec3 v_cubeMapUV;

uniform sampler2D u_texture;
uniform samplerCube u_textureCubemap;

void main()
{    
  vec3 cubeMapUV = normalize(v_cubeMapUV);    
  vec4 diffuse = textureCube(u_textureCubemap, cubeMapUV);

  gl_FragColor.rgb = diffuse;
}

结果是完全错误的: wrong result

我希望这样:

correct result

更新2

如果我将顶点位置用作顶点着色器中的立方体贴图坐标,则纹理看起来会在侧面拉伸并且在某些地方变形:

v_cubeMapUV = a_position.xyz;

stretched texture

distorted texture

我上传了euro.blendeuro.objcubemap文件进行审核。

1 个答案:

答案 0 :(得分:2)

该代码仅适用于以(0,0,0)为中心的网格,即使不是这种情况,或者即使(0,0,0)不在网格内也会出现伪像...

我将从计算您的网格物体的 BBOX BBOXmin(x0,y0,z0),BBOXmax(x1,y1,z1)开始,然后转换用于纹理坐标的位置,使其围绕其中心:

center = 0.5*(BBOXmin+BBOXmax);
texCoord = vec3(a_position-center);

但是,不均匀的顶点密度仍然会导致纹理缩放伪像,特别是如果BBOX边的大小相差太大。将其重新缩放为多维数据集将有所帮助:

vec3 center = 0.5*(BBOXmin+BBOXmax);  // center of BBOX
vec3 size   =      BBOXmax-BBOXmin;   // size of BBOX
vec3 r      =      a_position-center; // position centered around center of BBOX
r.x/=size.x; // rescale it to cube BBOX
r.y/=size.y;
r.z/=size.z;
texCoord = r;

同样,如果BBOX的中心不在网格内,那么这将无法工作...

我对反射部分不清楚,您是否得到了一些图像/屏幕截图?

[Edit1]简单示例

我这样看(没有上面提到的中心偏移和纵横比校正):

[顶点]

//------------------------------------------------------------------
#version 420 core
//------------------------------------------------------------------
uniform mat4x4 tm_l2g;
uniform mat4x4 tm_g2s;
layout(location=0) in vec3 pos;
layout(location=1) in vec4 col;

out smooth vec4 pixel_col;
out smooth vec3 pixel_txr;
//------------------------------------------------------------------
void main(void)
    {
    pixel_col=col;
    pixel_txr=(tm_l2g*vec4(pos,0.0)).xyz;
    gl_Position=tm_g2s*tm_l2g*vec4(pos,1.0);
    }
//------------------------------------------------------------------

[片段]

//------------------------------------------------------------------
#version 420 core
//------------------------------------------------------------------
in smooth vec4 pixel_col;
in smooth vec3 pixel_txr;

uniform samplerCube txr_skybox;

out layout(location=0) vec4 frag_col;

//------------------------------------------------------------------
void main(void)
    {
    frag_col=texture(txr_skybox,pixel_txr);
    }
//------------------------------------------------------------------

在这里预览:

preview reflective/transparent

前几帧中的白色环面使用固定功能,其余部分使用着色器。如您所见,我唯一使用的输入是顶点position,color和变换矩阵tm_l2g,它们从网格坐标转换为全局世界,而tm_g2s则保留透视投影...

如您所见,我使用与渲染模型时相同的CUBE MAP纹理来渲染 BBOX ,因此看起来像很酷的反射/透明度效果:)(这不是故意的)。

无论如何,当我换线

pixel_txr=(tm_l2g*vec4(pos,0.0)).xyz;

进入:

pixel_txr=pos;

在我的顶点着色器中,对象将再次变为实体:

Preview solid

您可以通过传递两个纹理坐标向量并将片段中的两个纹理像素取到以一定比率将它们相加在一起来进行合并。粗略地说,您需要传递2个多维数据集贴图纹理,一个用于对象,一个用于天空盒...

红色警告来自我的CPU端代码,提醒我我正在尝试设置着色器中不存在的制服(因为我从bump mapping example进行此操作而未更改CPU端代码...)< / p>

[Edit1]此处具有偏移的网格预览

offset

顶点进行了一些更改(只是添加了答案中描述的偏移量):

//------------------------------------------------------------------
#version 420 core
//------------------------------------------------------------------
uniform mat4x4 tm_l2g;
uniform mat4x4 tm_g2s;
uniform vec3 center=vec3(0.0,0.0,2.0);

layout(location=0) in vec3 pos;
layout(location=1) in vec4 col;

out smooth vec4 pixel_col;
out smooth vec3 pixel_txr;
//------------------------------------------------------------------
void main(void)
    {
    pixel_col=col;
    pixel_txr=pos-center;
    gl_Position=tm_g2s*tm_l2g*vec4(pos,1.0);
    }
//------------------------------------------------------------------

因此,通过偏移中心点,您可以消除奇异点变形,但是正如我在评论中提到的任意网格一样,总是存在一些廉价的纹理技巧而不是适当的纹理坐标的变形。

请注意,我的网格已调整大小/规格化(可悲的是,我不记得它的<-1,+1>范围还是其他ona,并且懒得在我测试过的GLSL引擎的源代码中进行挖掘),因此偏移量可能有在您的环境中具有不同的幅度以达到相同的结果。