如何使用立方体贴图纹理非展开的模型

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用立方体贴图纹理非展开的模型相关的知识,希望对你有一定的参考价值。

我有很多未解开的模型(它们没有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文件进行审核。

答案

该代码仅适用于以(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端代码......)

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

offset

Vertex稍微改变了一下(刚刚添加了答案中描述的偏移量):

//------------------------------------------------------------------
#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引擎的源代码中)所以偏移可能在你的环境中有不同的幅度来实现同样的结果。

以上是关于如何使用立方体贴图纹理非展开的模型的主要内容,如果未能解决你的问题,请参考以下文章

在片段着色器中使用 textureCube 访问环境贴图失败

尝试对立方体贴图纹理进行采样时出现 GL_INVALID_OPERATION

使用vue学习three.js之加载和使用纹理-使用CubeCamera创建反光效果,动态环境贴图实现,立方体全景贴图

CUDA 立方体贴图纹理

使用立方体贴图(不是反射贴图)对球体进行纹理处理

全向阴影贴图