簡體   English   中英

使用2D紋理解決方法的WebGL / three.js中的3D紋理?

[英]3D texture in WebGL/three.js using 2D texture workaround?

我想對我在WebGL中渲染的對象使用一些3D紋理。 我正在片段着色器中使用以下方法,如WebGL和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);
}

問題是我可以使用的最大3D紋理是64x64x64(因為最大2D紋理寬度是4096 = 64 * 64)。 如果可能的話,我想嘗試使用更大的紋理,所以我想看看是否有人建議使用更高分辨率的3D紋理和類似的解決方法。 據推測,我應該能夠組織2D紋理,使得我可以水平和垂直排列3D切片,但到目前為止,我的google-fu還沒有找到可行的解決方案。

似乎相對直截了當。 如果您想要沿着圖像向下移動,則必須計算v紋理坐標,為切片選擇正確的 要做到這一點,您需要知道紋理中有多少行以及每行有多少個切片

// 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;
}

這是一個片段

 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> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM