Domanda

Vorrei usare alcune strutture 3D per oggetti che sto rendendo in WebGL.Attualmente sto utilizzando il seguente metodo in un frammento shader, come suggerito su differenze WebGL e OpenGL :

// tex is a texture with each slice of the cube placed horizontally across the texture.
// texCoord is a 3d texture coord
// size is the size if the cube in pixels.

vec4 sampleAs3DTexture(sampler2D tex, vec3 texCoord, float size) {
   float sliceSize = 1.0 / size;                         // space of 1 slice
   float slicePixelSize = sliceSize / size;              // space of 1 pixel
   float sliceInnerSize = slicePixelSize * (size - 1.0); // space of size pixels
   float zSlice0 = min(floor(texCoord.z * size), size - 1.0);
   float zSlice1 = min(zSlice0 + 1.0, size - 1.0);
   float xOffset = slicePixelSize * 0.5 + texCoord.x * sliceInnerSize;
   float s0 = xOffset + (zSlice0 * sliceSize);
   float s1 = xOffset + (zSlice1 * sliceSize);
   vec4 slice0Color = texture2D(tex, vec2(s0, texCoord.y));
   vec4 slice1Color = texture2D(tex, vec2(s1, texCoord.y));
   float zOffset = mod(texCoord.z * size, 1.0);
   return mix(slice0Color, slice1Color, zOffset);
}
.

Il problema è che la più grande texture 3D che posso utilizzare è 64x64x64 (dal momento che la larghezza massima di texture 2D è 4096= 64 * 64).Vorrei provare a utilizzare trame più grandi, se possibile, quindi vorrei vedere se qualcuno ha suggerimenti per l'utilizzo di tessiture 3D di risoluzione più elevata con una soluzione simile.Presumibilmente, dovrei essere in grado di organizzare la struttura 2D in modo tale da avere le fette 3D organizzate orizzontalmente e verticalmente, ma il mio Google-Fu non è stato in grado di trovare una soluzione praticabile finora.

È stato utile?

Soluzione

sembra relativamente semplice.Se vuoi andare giù anche l'immagine, dovrai calcolare una coordinata di texture v che seleziona la riga giusta per la tua fetta.Per fare ciò dovrai sapere quante righe ci sono nella consistenza e quante fette per riga

// tex is a texture with each slice of the cube placed in grid in a texture.
// texCoord is a 3d texture coord
// size is the size if the cube in pixels.
// slicesPerRow is how many slices there are across the texture
// numRows is the number of rows of slices

vec2 computeSliceOffset(float slice, float slicesPerRow, vec2 sliceSize) {
  return sliceSize * vec2(mod(slice, slicesPerRow), 
                          floor(slice / slicesPerRow));
}

vec4 sampleAs3DTexture(
    sampler2D tex, vec3 texCoord, float size, float numRows, float slicesPerRow) {
  float slice   = texCoord.z * size;
  float sliceZ  = floor(slice);                         // slice we need
  float zOffset = fract(slice);                         // dist between slices

  vec2 sliceSize = vec2(1.0 / slicesPerRow,             // u space of 1 slice
                        1.0 / numRows);                 // v space of 1 slice

  vec2 slice0Offset = computeSliceOffset(sliceZ, slicesPerRow, sliceSize);
  vec2 slice1Offset = computeSliceOffset(sliceZ + 1.0, slicesPerRow, sliceSize);

  vec2 slicePixelSize = sliceSize / size;               // space of 1 pixel
  vec2 sliceInnerSize = slicePixelSize * (size - 1.0);  // space of size pixels

  vec2 uv = slicePixelSize * 0.5 + texCoord.xy * sliceInnerSize;
  vec4 slice0Color = texture2D(tex, slice0Offset + uv);
  vec4 slice1Color = texture2D(tex, slice1Offset + uv);
  return mix(slice0Color, slice1Color, zOffset);
  return slice0Color;
}
.

Ecco uno snippet

var canvas = document.getElementById("c");
var gl = canvas.getContext("webgl");
var program = twgl.createProgramFromScripts(
    gl, ["vshader", "fshader"], ["a_position"]);
gl.useProgram(program);

var sizeLoc = gl.getUniformLocation(program, "u_size");
var numRowsLoc = gl.getUniformLocation(program, "u_numRows");
var slicesPerRowLoc = gl.getUniformLocation(program, "u_slicesPerRow");

// make sphere triangles
var numDivisionsAround = 32;
var numDivisionsDown = 16;
var verts = [];
for (var v = 0; v < numDivisionsDown; ++v) {
  var v0 = Math.sin((v + 0) / numDivisionsDown * Math.PI);
  var v1 = Math.sin((v + 1) / numDivisionsDown * Math.PI);
  var y0 = Math.cos((v + 0) / numDivisionsDown * Math.PI);
  var y1 = Math.cos((v + 1) / numDivisionsDown * Math.PI);
  for (var h = 0; h < numDivisionsAround; ++h) {
    var a0 = (h + 0) * Math.PI * 2 / numDivisionsAround;
    var a1 = (h + 1) * Math.PI * 2 / numDivisionsAround;
    var x00 = Math.sin(a0) * v0;
    var x10 = Math.sin(a1) * v0;
    var x01 = Math.sin(a0) * v1;
    var x11 = Math.sin(a1) * v1;
    var z00 = Math.cos(a0) * v0;
    var z10 = Math.cos(a1) * v0;
    var z01 = Math.cos(a0) * v1;
    var z11 = Math.cos(a1) * v1;
    verts.push(
      x00, y0, z00, 
      x10, y0, z10, 
      x01, y1, z01,
      
      x01, y1, z01, 
      x10, y0, z10, 
      x11, y1, z11);
  }
}


var vertBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.STATIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);

// Make 3D texture
var size = 8;
var slicesPerRow = 4;
var numRows = Math.floor((size + slicesPerRow - 1) / slicesPerRow); 
var pixels = new Uint8Array(size * slicesPerRow * size * numRows * 4);
var pixelsAcross = slicesPerRow * size;
for (var slice = 0; slice < size; ++slice) {
    var row = Math.floor(slice / slicesPerRow);
    var xOff = slice % slicesPerRow * size;
    var yOff = row * size;    
    for (var y = 0; y < size; ++y) {
        for (var x = 0; x < size; ++x) {
            var offset = ((yOff + y) * pixelsAcross + xOff + x) * 4;
            pixels[offset + 0] = x / size * 255;
            pixels[offset + 1] = y / size * 255;
            pixels[offset + 2] = slice / size * 255;
            pixels[offset + 3] = 255;
        }
    }
}
// put this in a 2d canvas for debugging
var c = document.createElement("canvas");
c.width = size * slicesPerRow;
c.height = size * numRows;
document.body.appendChild(c);
var ctx = c.getContext("2d");
var id = ctx.getImageData(0, 0, c.width, c.height);
var numBytes = c.width * c.height * 4;
for (var ii = 0; ii < numBytes; ++ii) {
    id.data[ii] = pixels[ii];
}
ctx.putImageData(id, 0, 0);

var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size * slicesPerRow, numRows * size, 0,
              gl.RGBA, gl.UNSIGNED_BYTE, pixels);

var log = console.log.bind(console);
log("size        : " + size);
log("numRows     : " + numRows);
log("slicesPerRow: " + slicesPerRow);

gl.uniform1f(sizeLoc, size);
gl.uniform1f(numRowsLoc, numRows);
gl.uniform1f(slicesPerRowLoc, slicesPerRow);

// draw circle
gl.enable(gl.DEPTH_TEST);
gl.drawArrays(gl.TRIANGLES, 0, verts.length / 3);
.
canvas { 
    border: 1px solid black;
    margin: 2px;
}
.
<script src="https://twgljs.org/dist/3.x/twgl.min.js"></script>
<script id="vshader" type="whatever">
    attribute vec4 a_position;
    varying vec3 v_texcoord;
    void main() {
      gl_Position = a_position;
      v_texcoord = a_position.xyz * 0.5 + 0.5;
    }    
</script>
<script id="fshader" type="whatever">
    precision mediump float;
    
    // tex is a texture with each slice of the cube placed in grid in a texture.
    // texCoord is a 3d texture coord
    // size is the size if the cube in pixels.
    // slicesPerRow is how many slices there are across the texture
    // numRows is the number of rows of slices

    vec2 computeSliceOffset(float slice, float slicesPerRow, vec2 sliceSize) {
      return sliceSize * vec2(mod(slice, slicesPerRow), 
                              floor(slice / slicesPerRow));
    }
    
    vec4 sampleAs3DTexture(
        sampler2D tex, vec3 texCoord, float size, float numRows, float slicesPerRow) {
      float slice   = texCoord.z * size;
      float sliceZ  = floor(slice);                         // slice we need
      float zOffset = fract(slice);                         // dist between slices
    
      vec2 sliceSize = vec2(1.0 / slicesPerRow,             // u space of 1 slice
                            1.0 / numRows);                 // v space of 1 slice
    
      vec2 slice0Offset = computeSliceOffset(sliceZ, slicesPerRow, sliceSize);
      vec2 slice1Offset = computeSliceOffset(sliceZ + 1.0, slicesPerRow, sliceSize);
    
      vec2 slicePixelSize = sliceSize / size;               // space of 1 pixel
      vec2 sliceInnerSize = slicePixelSize * (size - 1.0);  // space of size pixels

      vec2 uv = slicePixelSize * 0.5 + texCoord.xy * sliceInnerSize;
      vec4 slice0Color = texture2D(tex, slice0Offset + uv);
      vec4 slice1Color = texture2D(tex, slice1Offset + uv);
      return mix(slice0Color, slice1Color, zOffset);
      return slice0Color;
    }
    
    varying vec3 v_texcoord;
    
    uniform float u_size;
    uniform float u_numRows;
    uniform float u_slicesPerRow;    
    uniform sampler2D u_texture;
    
    void main() {
         gl_FragColor = sampleAs3DTexture(
             u_texture, v_texcoord, u_size, u_numRows, u_slicesPerRow);
    }
</script>
<canvas id="c" width="400" height="400"></canvas>
.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top