Как реализовать textureCube с использованием 6 sampler2D - PullRequest
0 голосов
/ 02 ноября 2018

До того, как я использовал samplerCube для рендеринга куба

Это мой предыдущий фрагмент кода Шейдера

"uniform samplerCube tCubeTgt;",
"varying vec3 posTgt;",
"void main() {",
    "vec4 reflectedColorTgt = textureCube( tCubeTgt, vec3( -posTgt.x, posTgt.yz ) );",
    "gl_FragColor = reflectedColorTgt ;",
"}"

Теперь я хочу использовать 6 sampler2D для рендеринга куба.

что мне делать

1 Ответ

0 голосов
/ 02 ноября 2018

Почему?

В любом случае, если посмотреть, как работает кубическое отображение, в спецификации OpenGL ES 2.0 есть функция и таблица, показывающая, как работает кубическое отображение

enter image description here

откуда sc, tc и ma взяты из этой таблицы

Major Axis Direction|        Target             |sc |tc |ma |
--------------------+---------------------------+---+---+---+
       +rx          |TEXTURE_CUBE_MAP_POSITIVE_X|−rz|−ry| rx|
       −rx          |TEXTURE_CUBE_MAP_NEGATIVE_X| rz|−ry| rx|
       +ry          |TEXTURE_CUBE_MAP_POSITIVE_Y| rx| rz| ry|
       −ry          |TEXTURE_CUBE_MAP_NEGATIVE_Y| rx|−rz| ry|
       +rz          |TEXTURE_CUBE_MAP_POSITIVE_Z| rx|−ry| rz|
       −rz          |TEXTURE_CUBE_MAP_NEGATIVE_Z|−rx|−ry| rz|
--------------------+---------------------------+---+---+---+

Таблица 3.21: Выбор изображений кубической карты на основе направления большой оси текстурных координат

Используя это, вы можете создавать функции, которые будут применять ту же логику, используя 6 двумерных текстур вместо одной кубической карты

"use strict";

/* global document, twgl, requestAnimationFrame */

const vs = `
uniform mat4 u_model;
uniform mat4 u_view;
uniform mat4 u_projection;
uniform vec3 u_camera;

attribute vec4 position;
attribute vec3 normal;

varying vec3 v_normal;
varying vec3 v_eyeToSurface;

void main() {
  vec4 world = u_model * position;
  gl_Position = u_projection * u_view * world;
  v_eyeToSurface = world.xyz - u_camera;
  v_normal = (u_model * vec4(normal, 0)).xyz;
}
`;
const fs = `
precision mediump float;

varying vec3 v_eyeToSurface;
varying vec3 v_normal;

uniform sampler2D u_textures[6];

void cubemap(vec3 r, out float texId, out vec2 st) {
   vec3 uvw;
   vec3 absr = abs(r);
   if (absr.x > absr.y && absr.x > absr.z) {
     // x major
     float negx = step(r.x, 0.0);
     uvw = vec3(r.zy, absr.x) * vec3(mix(-1.0, 1.0, negx), -1, 1);
     texId = negx;
   } else if (absr.y > absr.z) {
     // y major
     float negy = step(r.y, 0.0);
     uvw = vec3(r.xz, absr.y) * vec3(1.0, mix(1.0, -1.0, negy), 1.0);
     texId = 2.0 + negy;
   } else {
     // z major
     float negz = step(r.z, 0.0);
     uvw = vec3(r.xy, absr.z) * vec3(mix(1.0, -1.0, negz), -1, 1);
     texId = 4.0 + negz;
   }
   st = vec2(uvw.xy / uvw.z + 1.) * .5;
}

vec4 texCubemap(vec3 uvw) {
  float texId;
  vec2 st;
  cubemap(uvw, texId, st);
  vec4 color = vec4(0);
  for (int i = 0; i < 6; ++i) {
    vec4 side = texture2D(u_textures[i], st);
    float select = step(float(i) - 0.5, texId) * 
                   step(texId, float(i) + .5);
    color = mix(color, side, select);
  }
  return color;
}

void main() {
  vec3 normal = normalize(v_normal);
  vec3 eyeToSurface = normalize(v_eyeToSurface);
  gl_FragColor = texCubemap(reflect(eyeToSurface, normal));
}
`;

const m4 = twgl.m4;
const gl = document.getElementById("c").getContext("webgl");
// compile shaders, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);

// create buffers
const models = [
  twgl.primitives.createSphereBufferInfo(gl, 1, 12, 8),
  twgl.primitives.createCubeBufferInfo(gl, 1.5),
  twgl.primitives.createTorusBufferInfo(gl, .7, .5, 12, 8),
];

const textures = twgl.createTextures(gl, {
  posx: { minMag: gl.LINEAR, wrap: gl.CLAMP_TO_EDGE, crossOrigin: "anonymous", src:'https://twgljs.org/examples/images/yokohama/posx.jpg', },
  negx: { minMag: gl.LINEAR, wrap: gl.CLAMP_TO_EDGE, crossOrigin: "anonymous", src:'https://twgljs.org/examples/images/yokohama/negx.jpg', },
  posy: { minMag: gl.LINEAR, wrap: gl.CLAMP_TO_EDGE, crossOrigin: "anonymous", src:'https://twgljs.org/examples/images/yokohama/posy.jpg', },
  negy: { minMag: gl.LINEAR, wrap: gl.CLAMP_TO_EDGE, crossOrigin: "anonymous", src:'https://twgljs.org/examples/images/yokohama/negy.jpg', },
  posz: { minMag: gl.LINEAR, wrap: gl.CLAMP_TO_EDGE, crossOrigin: "anonymous", src:'https://twgljs.org/examples/images/yokohama/posz.jpg', },
  negz: { minMag: gl.LINEAR, wrap: gl.CLAMP_TO_EDGE, crossOrigin: "anonymous", src:'https://twgljs.org/examples/images/yokohama/negz.jpg', },
});

const uniforms = {
  u_textures: [
    textures.posx,
    textures.negx,
    textures.posy,
    textures.negy,
    textures.posz,
    textures.negz,
  ],
};

function render(time) {
  time *= 0.001;
  twgl.resizeCanvasToDisplaySize(gl.canvas);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  
  gl.enable(gl.DEPTH_TEST);
  gl.enable(gl.CULL_FACE);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  const fov = 30 * Math.PI / 180;
  const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
  const zNear = 0.5;
  const zFar = 20;
  const projection = m4.perspective(fov, aspect, zNear, zFar);
  
  const eye = [
    Math.sin(time) * 7, 
    Math.sin(time * .5) * 3, 
    Math.cos(time) * 7,
  ];
  const target = [0, 0, 0];
  const up = [0, 1, 0];

  const camera = m4.lookAt(eye, target, up);
  const view = m4.inverse(camera);

  uniforms.u_camera = eye;
  uniforms.u_projection = projection;
  uniforms.u_view = view;
  
  gl.useProgram(programInfo.program);
  
  models.forEach((bufferInfo, ndx) => {
    let u = ndx / (models.length - 1) * 2 - 1;
    let model = m4.translation([u * (models.length - 1), 0, 0]);
    model = m4.rotateY(model, time * (ndx + 1) * 0.7);
    uniforms.u_model = m4.rotateX(model, time * (ndx + 1) * 0.2);

    twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
    twgl.setUniforms(programInfo, uniforms);
    gl.drawElements(gl.TRIANGLES, bufferInfo.numElements, gl.UNSIGNED_SHORT, 0);
  });

  requestAnimationFrame(render);
}
requestAnimationFrame(render);
body {
  margin: 0;
}
canvas {
  display: block;
  width: 100vw;
  height: 100vh;
}
<canvas id="c"></canvas>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>

Но вы увидите, что есть много проблем. Одна проблема заключается в том, что делать на краю. GPU может фильтровать по краям? Нам нужно что-то добавить, чтобы сделать это. Также мы не можем использовать произвольный доступ к сэмплерам и не можем условно обращаться к сэмплерам, что означает, что делать это с 6 2-мерными текстурами вместо одной кубической карты будет намного медленнее

...