Как текстурировать не развернутую модель, используя кубическую карту - PullRequest
3 голосов
/ 29 апреля 2019

У меня есть много моделей, которые не развернуты (у них нет УФ-координат).Они довольно сложны, чтобы развернуть их.Таким образом, я решил текстурировать их, используя бесшовную кубическую карту:

[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.blend , euro.obj и cubemap файлы для просмотра.

1 Ответ

2 голосов
/ 29 апреля 2019

этот код работает только для сеток, центрированных вокруг (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] простой пример

Я вижу это так (без упомянутых выше корректировок смещения центра и соотношения сторон):

[Vertex]

//------------------------------------------------------------------
#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, который содержит перспективную проекцию ...

Как вы можете видеть, я визуализирую BBOX с той же текстурой CUBE MAP, которую я использую для рендеринга модели, чтобы она выглядела как крутой эффект отражения / прозрачности :) (который не был намеренным).

В любом случае, когда я меняю линию

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

в

pixel_txr=pos;

В моем вершинном шейдере объект снова будет твердым:

Preview solid

Вы можете объединить оба, передав два вектора координат текстуры и выбрав два фрагмента во фрагменте, добавив их с некоторым соотношением вместе. Конечно, вам нужно будет передать 2 текстуры карты куба, одну для объекта и одну для скайбокса ...

Красные предупреждения исходят из моего кода на стороне процессора, напоминая мне, что я пытаюсь установить униформу, которой нет в шейдерах (как я делал это из примера bump mapping без изменения кода на стороне процессора. ..)

[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, в котором я проверял это), чтобы смещение могло иметь различную величину в вашей среде, чтобы достичь того же результата.

...