Mipmap三个.js中的一个行星

Mipmap a planet in three.js?

本文关键字:一个 行星 三个 js Mipmap      更新时间:2023-09-26

所以我最近了解了mipmapping的定义,但不确定如何在three.js.中正确使用该技术

我看了这个例子:http://threejs.org/examples/webgl_materials_texture_manualmipmap.html

我也看到了这一点:http://threejs.org/examples/#webgl_materials_texture_anisotropy

两者似乎都使用了mipmapping。第一个例子有这段代码:

function mipmap( size, color ) {
            var imageCanvas = document.createElement( "canvas" ),
                context = imageCanvas.getContext( "2d" );
            imageCanvas.width = imageCanvas.height = size;
            context.fillStyle = "#444";
            context.fillRect( 0, 0, size, size );
            context.fillStyle = color;
            context.fillRect( 0, 0, size / 2, size / 2 );
            context.fillRect( size / 2, size / 2, size / 2, size / 2 );
            return imageCanvas;
        }
        var canvas = mipmap( 128, '#f00' );
        var textureCanvas1 = new THREE.CanvasTexture( canvas );
        textureCanvas1.mipmaps[ 0 ] = canvas;
        textureCanvas1.mipmaps[ 1 ] = mipmap( 64, '#0f0' );
        textureCanvas1.mipmaps[ 2 ] = mipmap( 32, '#00f' );
        textureCanvas1.mipmaps[ 3 ] = mipmap( 16, '#400' );
        textureCanvas1.mipmaps[ 4 ] = mipmap( 8,  '#040' );
        textureCanvas1.mipmaps[ 5 ] = mipmap( 4,  '#004' );
        textureCanvas1.mipmaps[ 6 ] = mipmap( 2,  '#044' );
        textureCanvas1.mipmaps[ 7 ] = mipmap( 1,  '#404' );
        textureCanvas1.repeat.set( 1000, 1000 );
        textureCanvas1.wrapS = THREE.RepeatWrapping;
        textureCanvas1.wrapT = THREE.RepeatWrapping;
        var textureCanvas2 = textureCanvas1.clone();
        textureCanvas2.magFilter = THREE.NearestFilter;
        textureCanvas2.minFilter = THREE.NearestMipMapNearestFilter;
        materialCanvas1 = new THREE.MeshBasicMaterial( { map: textureCanvas1 } );
        materialCanvas2 = new THREE.MeshBasicMaterial( { color: 0xffccaa, map: textureCanvas2 } );
        var geometry = new THREE.PlaneBufferGeometry( 100, 100 );
        var meshCanvas1 = new THREE.Mesh( geometry, materialCanvas1 );
        meshCanvas1.rotation.x = -Math.PI / 2;
        meshCanvas1.scale.set(1000, 1000, 1000);
        var meshCanvas2 = new THREE.Mesh( geometry, materialCanvas2 );
        meshCanvas2.rotation.x = -Math.PI / 2;
        meshCanvas2.scale.set( 1000, 1000, 1000 );

不清楚的是:

textureCanvas1.mipmaps[ 1 ] = mipmap( 64, '#0f0' );

以及2d上下文的使用。

不管怎样,考虑到这些例子的性质,我仍然不知道如何绘制行星的mipmap。所以,是的,我不确定如何正确地斜接一个球体。首先,我需要我的行星/球体由单独的部分组成,这样我就可以在球体的每个部分上放置不同的破碎纹理。然后我创造了两种尺寸变化的力量,但那又怎样呢?

所以我的问题是,当用于立方体、球体等时,three.js中的mipmapping看起来怎么样?简化的演示将非常受欢迎,因为现有的示例(很少)看起来要么过于臃肿,要么没有文档。

编辑:另一个用户在stackoverflow发布了这个:

var texture = THREE.ImageUtils.loadTexture( 'images/512.png', undefined, function() {
    texture.repeat.set( 1, 1 );
    texture.mipmaps[ 0 ] = texture.image;
    texture.generateMipmaps = true;
    texture.needsUpdate = true;
};

mipmaps的关键似乎是texture.mipmaps[]。不过这里的人只指定了一张图片。我们不应该提供各种图像,让电脑根据你的距离来决定哪种合适吗?不确定此mipmapping是如何工作的。

Mipmapping

Mipmapping是一种基于每个纹理应用的纹理渲染技术。它的基本要点是,当启用mipmapping时,GPU将使用较小版本的纹理来渲染曲面,具体取决于曲面离相机的距离。

为了使用mipmapping,您需要为纹理设置一组mipmappings;mipmaps是纹理的较小版本。你可以自己提供这些mipmap,在过去你可能不得不这样做,但使用最近的图形API(OpenGL>=3.0),它们可以自动生成如果您所做的只是将基本纹理贴图应用于球体的表面,那么您不太可能需要生成自己的mipmaps

Mipmapping与正在进行纹理处理的对象的3D形状没有任何关系。无论您是将纹理应用于立方体、球体还是任何其他模型,作为程序员,启用mipmapping所需的步骤都是相同的。您不需要启用mipmapping来渲染纹理,尽管它可能会使纹理看起来更漂亮。

这在Three.js中对你的影响

默认情况下在three.js中,您无需执行任何操作即可为纹理生成mipmaps。参考纹理的three.js文档,有一个generateMipmaps属性控制mipmaps的自动生成,默认为true。此功能在此处的渲染器中实现。这意味着你需要做的最低限度的mipmated纹理是这样的:

var texture1 = THREE.ImageUtils.loadTexture("surface.png");
// our mipmaps will generate automatically now!

还有一个mipmaps属性,可以手动填充mipmap图像,如您提供的示例所示。奇怪的是,一个未记录的特性是,如果这个数组不为空,它将禁用自动生成mipmap。你可以在这里看到它的来源。

分解示例

在瓷砖地板上绘画的第一个示例中,mipmap()函数在HTML画布上绘制2D纹理。它负责绘制您在地平面上看到的平铺纹理。然后,通过将这些纹理放入mipmaps阵列中,将它们加载为mipmap,这样它们就可以通过three.js.进行3D渲染

var canvas = mipmap( 128, '#f00' );
var textureCanvas1 = new THREE.CanvasTexture( canvas );
// manually set up some mipmaps
textureCanvas1.mipmaps[ 0 ] = canvas;
textureCanvas1.mipmaps[ 1 ] = mipmap( 64, '#0f0' );
textureCanvas1.mipmaps[ 2 ] = mipmap( 32, '#00f' );
textureCanvas1.mipmaps[ 3 ] = mipmap( 16, '#400' );
textureCanvas1.mipmaps[ 4 ] = mipmap( 8,  '#040' );
textureCanvas1.mipmaps[ 5 ] = mipmap( 4,  '#004' );
textureCanvas1.mipmaps[ 6 ] = mipmap( 2,  '#044' );
textureCanvas1.mipmaps[ 7 ] = mipmap( 1,  '#404' );

你注意到每个连续的mipmap都是两倍小吗?起始纹理(我们必须放在mipmaps[0]中)是128x128,第二个是64x64,第三个是32x32,依此类推。颜色(#0f0#00f#400等)是瓷砖上出现奇怪彩虹效果的原因。它们的颜色不同,以显示不同mipmap的边缘。

奖励:各向异性

第二个例子用于展示一种称为各向异性滤波的效果,这是在mipmapping之上的进一步增强;它根据从相机的距离到相机的视角来选择要使用的纹理大小。这可以使远处的纹理在远离相机时看起来更好。

var maxAnisotropy = renderer.getMaxAnisotropy();
var texture1 = THREE.ImageUtils.loadTexture( "textures/crate.gif" );
// no need to generate mipmaps here, we get them automatically!
texture1.anisotropy = maxAnisotropy;
texture1.wrapS = texture1.wrapT = THREE.RepeatWrapping;
texture1.repeat.set( 512, 512 );

你注意到左边(texture1)的板条箱纹理比右边(texture2)清晰得多,也不那么模糊了吗?

结果

我在一个plunker中放了一个更深入的例子,希望能让它更清楚地了解所有这些场景中发生的事情。一些注意事项:

  • 当你向上倾斜相机时,左上角(没有mipmapping)有一个非常明显的云纹图案。这就是为什么我们需要mipmapping
  • 右上角(mipmapping)看起来更好,但在远处仍然很模糊。为什么
  • 左下角(彩色mipmap)显示了原因。模糊是由线性滤波器将所有mipmap插值在一起引起的。当我们离相机越来越远时,就会使用较小的图像,用颜色表示
  • 右下角(各向异性过滤)应该看起来最好,使纹理看起来清晰,无论它们离得多远