AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 76984896
Accepted
gman
gman
Asked: 2023-08-27 05:23:50 +0800 CST2023-08-27 05:23:50 +0800 CST 2023-08-27 05:23:50 +0800 CST

根据不同的 texcoord 计算 mip 级别选择

  • 772

即使问题中的示例是 WebGL,也将其标记为 OpenGL,因为 OpenGL 领域专家应该能够回答这个问题。这里有一个 OpenGL 存储库

我正在尝试以与采样器基于纹理坐标导数相同的方式计算纹理 mip 级别。

我在这里和其他地方看到了很多答案。例如

  • 如何访问 GLSL 片段着色器纹理中的自动 mipmap 级别?
  • OpenGL的mipmap级别计算的推导?
  • 使用 dFdx/dFdy 计算 Mipmap 级别

所有这 3 个都说计算是

   vec2  dx_vtc        = dFdx(texture_coordinate);
   vec2  dy_vtc        = dFdy(texture_coordinate);
   float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));

   mip_level = 0.5 * log2(delta_max_sqr);

鉴于此,我写了一个测试。在测试中我有 2 个着色器。

  • 第一个着色器使用纹理坐标和采样纹理来绘制四边形。纹理有 7 个 mip 级别,每个级别都是不同的纯色。当我增加纹理坐标的范围时,我应该看到不同的 mip 被选择(使用 NEAREST_MIPMAP_NEAREST)。这有效?

  • 第二个着色器通过使用上面的公式计算 mip 级别,然后使用该 mip 级别从表中选择颜色来绘制四边形,表中的颜色与纹理中的颜色相匹配。这不起作用?。我所看到的都是红色(第一种颜色)。

这是第二个着色器

#version 300 es
precision highp float;

in vec2 v_texCoord;

out vec4 outColor;

const vec4 colors[8] = vec4[8](
  vec4(  1,   0,   0, 1), // 0: red
  vec4(  1,   1,   0, 1), // 1: yellow
  vec4(  0,   1,   0, 1), // 2: green
  vec4(  0,   1,   1, 1), // 3: cyan
  vec4(  0,   0,   1, 1), // 4: blue
  vec4(  1,   0,   1, 1), // 5: magenta
  vec4(0.5, 0.5, 0.5, 1), // 6: gray
  vec4(  1,   1,   1, 1));// 7: white

void main() {
  vec2 dx = dFdx(v_texCoord);
  vec2 dy = dFdy(v_texCoord);
  float deltaMaxSq = max(dot(dx, dx), dot(dy, dy));
  float mipLevel = 0.5 * log2(deltaMaxSq);
  
  outColor = colors[int(mipLevel)];
}

也许我只是有一个错字,但我尝试了各种调试方法

  • 我尝试可视化第二个着色器中的纹理坐标。他们显然是正确的
  • 我尝试确保索引颜色有效。这就是作品。
  • 我尝试通过从着色器写入来可视化 mip 级别mipLevel / 7.0,因此当 mip 级别达到 7 时,四边形应该变得更亮。这是行不通的。

我究竟做错了什么?

html, body {
  margin: 0;
  font-family: monospace;
  height: 100%;
}
canvas {
  display: block;
  width: 100%;
  height: 100%;
}
<canvas id="c"></canvas>

<script type="module">
import * as twgl from 'https://twgljs.org/dist/5.x/twgl-full.module.js';

const vs = `#version 300 es
uniform mat4 u_worldViewProjection;
uniform mat3 u_texMat;

out vec2 v_texCoord;

const vec2 position[6] = vec2[6](
  vec2(0, 0),
  vec2(1, 0),
  vec2(0, 1),
  vec2(0, 1),
  vec2(1, 0),
  vec2(1, 1));

void main() {
  vec2 p = position[gl_VertexID];
  v_texCoord = (u_texMat * vec3(p, 1)).xy;
  gl_Position = u_worldViewProjection * vec4(p, 0, 1);
}
`;
const fsTex = `#version 300 es
precision highp float;

in vec2 v_texCoord;

uniform sampler2D u_tex;

out vec4 outColor;

void main() {
  outColor = texture(u_tex, v_texCoord);
}
`;
const fsMipLevel = `#version 300 es
precision highp float;

in vec2 v_texCoord;

out vec4 outColor;

const vec4 colors[8] = vec4[8](
  vec4(  1,   0,   0, 1), // 0: red
  vec4(  1,   1,   0, 1), // 1: yellow
  vec4(  0,   1,   0, 1), // 2: green
  vec4(  0,   1,   1, 1), // 3: cyan
  vec4(  0,   0,   1, 1), // 4: blue
  vec4(  1,   0,   1, 1), // 5: magenta
  vec4(0.5, 0.5, 0.5, 1), // 6: gray
  vec4(  1,   1,   1, 1));// 7: white

void main() {
  vec2 dx = dFdx(v_texCoord);
  vec2 dy = dFdy(v_texCoord);
  float deltaMaxSq = max(dot(dx, dx), dot(dy, dy));
  float mipLevel = 0.5 * log2(deltaMaxSq);
  
  // mipLevel = mod(gl_FragCoord.x / 16.0, 8.0);  // comment in to test we can use the colors

  outColor = colors[int(mipLevel)];

  // outColor = vec4(mipLevel / 7.0, 0, 0, 1);  // comment in to visualize another way
  // outColor = vec4(fract(v_texCoord), 0, 1);  // comment in to visualize texcoord
}
`;

const colors = [
  '#F00',
  '#FF0',
  '#0F0',
  '#0FF',
  '#00F',
  '#F0F',
  '#888',
  '#FFF',
];


function createMips(colors) {
  const ctx = document.createElement('canvas').getContext('2d');
  const numMips = colors.length;
  return colors.map((color, i) => {
    const size = 2 ** (numMips - i - 1);
    ctx.canvas.width = size;
    ctx.canvas.height = size;
    ctx.fillStyle = color;
    ctx.fillRect(0, 0, size, size);
    return ctx.getImageData(0, 0, size, size);
  });
}

function main() {
  const m4 = twgl.m4;
  const gl = document.getElementById("c").getContext("webgl2");
  if (!gl) {
    alert("Sorry, this example requires WebGL 2.0");  // eslint-disable-line
    return;
  }

  const texProgramInfo = twgl.createProgramInfo(gl, [vs, fsTex]);
  const mipProgramInfo = twgl.createProgramInfo(gl, [vs, fsMipLevel]);

  const texImage = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, texImage);
  const data = createMips(colors);
  data.forEach(({width, height, data}, level) => {
    gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
  });
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST);

  const lerp = (a, b, t) => a + (b - a) * t;

  function render(time) {
    time *= 0.001;
    twgl.resizeCanvasToDisplaySize(gl.canvas);
    gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
    gl.clearColor(0.3, 0.3, 0.3, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);

    const uniforms = {};

    const s = lerp(1, 128, Math.sin(time) * 0.5 + 0.5);
    uniforms.u_texMat = [
      s, 0, 0,
      0, s, 0,
      0, 0, 1,
    ];
    uniforms.u_worldViewProjection = m4.translation([-1.01, -0.5, 0]);

    gl.useProgram(texProgramInfo.program);
    twgl.setUniforms(texProgramInfo, uniforms);
    gl.drawArrays(gl.TRIANGLES, 0, 6);

    uniforms.u_worldViewProjection = m4.translation([0.01, -0.5, 0]);

    gl.useProgram(mipProgramInfo.program);
    twgl.setUniforms(mipProgramInfo, uniforms);
    gl.drawArrays(gl.TRIANGLES, 0, 6);

    requestAnimationFrame(render);
  }
  requestAnimationFrame(render);
}

main();
</script>

opengl
  • 1 1 个回答
  • 44 Views

1 个回答

  • Voted
  1. Best Answer
    Rabbid76
    2023-08-27T15:03:45+08:002023-08-27T15:03:45+08:00

    mipmap 级别还取决于纹理的大小。mipmap 级别是对应将多少(方形)纹理元素压缩到一个片段中的度量。在链接问题(如何在 GLSL 片段着色器纹理中访问自动 mipmap 级别?)的答案中,mipmap 级别是根据纹理坐标乘以纹理大小计算得出的:

    mip_map_level(textureCoord * textureSize(myTexture, 0));  
    

    您错过了代码中的那部分。所以公式应该是:

    vec2 size = vec2(128.0, 128.0); // size of the texture in your example
    vec2 dx = dFdx(v_texCoord * size);
    vec2 dy = dFdy(v_texCoord * size);
    float deltaMaxSq = max(dot(dx, dx), dot(dy, dy));
    float mipLevel = 0.5 * log2(deltaMaxSq);
    

    另外,当您查找颜色时,您需要对 mipmap 级别进行舍入:

    outColor = colors[int(mipLevel)];

    outColor = colors[int(mipLevel + 0.5)];
    

    html, body {
      margin: 0;
      font-family: monospace;
      height: 100%;
    }
    canvas {
      display: block;
      width: 100%;
      height: 100%;
    }
    <canvas id="c"></canvas>
    
    <script type="module">
    import * as twgl from 'https://twgljs.org/dist/5.x/twgl-full.module.js';
    
    const vs = `#version 300 es
    uniform mat4 u_worldViewProjection;
    uniform mat3 u_texMat;
    
    out vec2 v_texCoord;
    
    const vec2 position[6] = vec2[6](
      vec2(0, 0),
      vec2(1, 0),
      vec2(0, 1),
      vec2(0, 1),
      vec2(1, 0),
      vec2(1, 1));
    
    void main() {
      vec2 p = position[gl_VertexID];
      v_texCoord = (u_texMat * vec3(p, 1)).xy;
      gl_Position = u_worldViewProjection * vec4(p, 0, 1);
    }
    `;
    const fsTex = `#version 300 es
    precision highp float;
    
    in vec2 v_texCoord;
    
    uniform sampler2D u_tex;
    
    out vec4 outColor;
    
    void main() {
      outColor = texture(u_tex, v_texCoord);
    }
    `;
    const fsMipLevel = `#version 300 es
    precision highp float;
    
    in vec2 v_texCoord;
    
    out vec4 outColor;
    
    const vec4 colors[8] = vec4[8](
      vec4(  1,   0,   0, 1), // 0: red
      vec4(  1,   1,   0, 1), // 1: yellow
      vec4(  0,   1,   0, 1), // 2: green
      vec4(  0,   1,   1, 1), // 3: cyan
      vec4(  0,   0,   1, 1), // 4: blue
      vec4(  1,   0,   1, 1), // 5: magenta
      vec4(0.5, 0.5, 0.5, 1), // 6: gray
      vec4(  1,   1,   1, 1));// 7: white
    
    void main() {
      vec2 size = vec2(128.0, 128.0); // size of the texture in your example
      vec2 dx = dFdx(v_texCoord * size);
      vec2 dy = dFdy(v_texCoord * size);
      float deltaMaxSq = max(dot(dx, dx), dot(dy, dy));
      float mipLevel = 0.5 * log2(deltaMaxSq);
      
      // mipLevel = mod(gl_FragCoord.x / 16.0, 8.0);  // comment in to test we can use the colors
    
      outColor = colors[int(mipLevel + 0.5)];
    
      // outColor = vec4(mipLevel / 7.0, 0, 0, 1);  // comment in to visualize another way
      // outColor = vec4(fract(v_texCoord), 0, 1);  // comment in to visualize texcoord
    }
    `;
    
    const colors = [
      '#F00',
      '#FF0',
      '#0F0',
      '#0FF',
      '#00F',
      '#F0F',
      '#888',
      '#FFF',
    ];
    
    
    function createMips(colors) {
      const ctx = document.createElement('canvas').getContext('2d');
      const numMips = colors.length;
      return colors.map((color, i) => {
        const size = 2 ** (numMips - i - 1);
        ctx.canvas.width = size;
        ctx.canvas.height = size;
        ctx.fillStyle = color;
        ctx.fillRect(0, 0, size, size);
        return ctx.getImageData(0, 0, size, size);
      });
    }
    
    function main() {
      const m4 = twgl.m4;
      const gl = document.getElementById("c").getContext("webgl2");
      if (!gl) {
        alert("Sorry, this example requires WebGL 2.0");  // eslint-disable-line
        return;
      }
    
      const texProgramInfo = twgl.createProgramInfo(gl, [vs, fsTex]);
      const mipProgramInfo = twgl.createProgramInfo(gl, [vs, fsMipLevel]);
    
      const texImage = gl.createTexture();
      gl.bindTexture(gl.TEXTURE_2D, texImage);
      const data = createMips(colors);
      data.forEach(({width, height, data}, level) => {
        gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
      });
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST);
    
      const lerp = (a, b, t) => a + (b - a) * t;
    
      function render(time) {
        time *= 0.001;
        twgl.resizeCanvasToDisplaySize(gl.canvas);
        gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
        gl.clearColor(0.3, 0.3, 0.3, 1);
        gl.clear(gl.COLOR_BUFFER_BIT);
    
        const uniforms = {};
    
        const s = lerp(1, 128, Math.sin(time) * 0.5 + 0.5);
        uniforms.u_texMat = [
          s, 0, 0,
          0, s, 0,
          0, 0, 1,
        ];
        uniforms.u_worldViewProjection = m4.translation([-1.01, -0.5, 0]);
    
        gl.useProgram(texProgramInfo.program);
        twgl.setUniforms(texProgramInfo, uniforms);
        gl.drawArrays(gl.TRIANGLES, 0, 6);
    
        uniforms.u_worldViewProjection = m4.translation([0.01, -0.5, 0]);
    
        gl.useProgram(mipProgramInfo.program);
        twgl.setUniforms(mipProgramInfo, uniforms);
        gl.drawArrays(gl.TRIANGLES, 0, 6);
    
        requestAnimationFrame(render);
      }
      requestAnimationFrame(render);
    }
    
    main();
    </script>

    • 3

相关问题

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    使用 <font color="#xxx"> 突出显示 html 中的代码

    • 2 个回答
  • Marko Smith

    为什么在传递 {} 时重载解析更喜欢 std::nullptr_t 而不是类?

    • 1 个回答
  • Marko Smith

    您可以使用花括号初始化列表作为(默认)模板参数吗?

    • 2 个回答
  • Marko Smith

    为什么列表推导式在内部创建一个函数?

    • 1 个回答
  • Marko Smith

    我正在尝试仅使用海龟随机和数学模块来制作吃豆人游戏

    • 1 个回答
  • Marko Smith

    java.lang.NoSuchMethodError: 'void org.openqa.selenium.remote.http.ClientConfig.<init>(java.net.URI, java.time.Duration, java.time.Duratio

    • 3 个回答
  • Marko Smith

    为什么 'char -> int' 是提升,而 'char -> Short' 是转换(但不是提升)?

    • 4 个回答
  • Marko Smith

    为什么库中不调用全局变量的构造函数?

    • 1 个回答
  • Marko Smith

    std::common_reference_with 在元组上的行为不一致。哪个是对的?

    • 1 个回答
  • Marko Smith

    C++17 中 std::byte 只能按位运算?

    • 1 个回答
  • Martin Hope
    fbrereto 为什么在传递 {} 时重载解析更喜欢 std::nullptr_t 而不是类? 2023-12-21 00:31:04 +0800 CST
  • Martin Hope
    比尔盖子 您可以使用花括号初始化列表作为(默认)模板参数吗? 2023-12-17 10:02:06 +0800 CST
  • Martin Hope
    Amir reza Riahi 为什么列表推导式在内部创建一个函数? 2023-11-16 20:53:19 +0800 CST
  • Martin Hope
    Michael A fmt 格式 %H:%M:%S 不带小数 2023-11-11 01:13:05 +0800 CST
  • Martin Hope
    God I Hate Python C++20 的 std::views::filter 未正确过滤视图 2023-08-27 18:40:35 +0800 CST
  • Martin Hope
    LiDa Cute 为什么 'char -> int' 是提升,而 'char -> Short' 是转换(但不是提升)? 2023-08-24 20:46:59 +0800 CST
  • Martin Hope
    jabaa 为什么库中不调用全局变量的构造函数? 2023-08-18 07:15:20 +0800 CST
  • Martin Hope
    Panagiotis Syskakis std::common_reference_with 在元组上的行为不一致。哪个是对的? 2023-08-17 21:24:06 +0800 CST
  • Martin Hope
    Alex Guteniev 为什么编译器在这里错过矢量化? 2023-08-17 18:58:07 +0800 CST
  • Martin Hope
    wimalopaan C++17 中 std::byte 只能按位运算? 2023-08-17 17:13:58 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve