# WebGLCubeRenderTarget : render to a specific mipmap level

**URL:** <https://discourse.threejs.org/t/webglcuberendertarget-render-to-a-specific-mipmap-level/57400>\
**Category:** Questions\
**Tags:** render-target, webgl-renderer\
**Created:** [October 25, 2023, 3:48pm UTC](https://discourse.threejs.org/t/webglcuberendertarget-render-to-a-specific-mipmap-level/57400 "2023-10-25T15:48:14Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![gillesboisson](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/gillesboisson/32/39924_2.png) [@gillesboisson](https://discourse.threejs.org/u/gillesboisson)\
**Post date:** [October 25, 2023, 3:48pm UTC](https://discourse.threejs.org/t/webglcuberendertarget-render-to-a-specific-mipmap-level/57400/1 "2023-10-25T15:48:14Z")

</div>

I’m trying to bake cubemap in different mipmap levels. I found the option setRenderTarget on WebGLRenderer but it didn’t found a way to setup the WebGLCubeRenderTarget texture properly to support multi mipmal level.

In my example, the first Lod level is rendered but I have this error

`[.WebGL-0x252803b8c700] GL_INVALID_FRAMEBUFFER_OPERATION: Framebuffer is incomplete: Attachment has zero size.`

This certainly means there no allocate storage in texture for other mipmaps level.

```plaintext
 wrapCubeFromTexture(
    source: Texture,
    size: number,
    lodLayouts: CubemapWrapperLayout[]
  ) {
    this._material.uniforms.sourceTexture.value = source
    this._material.needsUpdate = true
    const oldRenderTarget = this.renderer.getRenderTarget()

    const textureLevels: CubeTexture[] = []
    const renderTarget = new WebGLCubeRenderTarget(size, {
      format: source.format,
      type: source.type,
      ...this.renderTargetOptions,
      depthBuffer: false,
      generateMipmaps: false,
    })

    for (let lod = 0; lod < lodLayouts.length; lod++) {
      const layout = lodLayouts[lod]
      const lodSize = size / Math.pow(2, lod)

      renderTarget.viewport.set(0, 0, lodSize, lodSize)

      const geometry = this.createGeometry(layout)
      const mesh = new Mesh(geometry, this._material)
      for (let faceIndex = 0; faceIndex < 6; faceIndex++) {
        geometry.drawRange.start = faceIndex * 6
        this.renderer.setRenderTarget(renderTarget, faceIndex, lod)
        this.renderer.render(mesh, this._camera)
      }

      geometry.dispose()

      textureLevels.push(renderTarget.texture)
    }

    const cubemap = textureLevels.shift() as CubeTexture

    this.renderer.setRenderTarget(oldRenderTarget)
    console.log('cubemap', cubemap)
    return cubemap
  }
}

```

---

<div class="post-metadata">

**Author:** ![Mugen87](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mugen87/32/5645_2.png) [@Mugen87](https://discourse.threejs.org/u/Mugen87)\
**Post date:** [October 25, 2023, 4:36pm UTC](https://discourse.threejs.org/t/webglcuberendertarget-render-to-a-specific-mipmap-level/57400/2 "2023-10-25T16:36:40Z")

</div>

I think the official example [webgl\_materials\_cubemap\_render\_to\_mipmaps](https://threejs.org/examples/#webgl_materials_cubemap_render_to_mipmaps) should do what you are looking for. Can you use it as a code template?

---

<div class="post-metadata">

**Author:** ![gillesboisson](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/gillesboisson/32/39924_2.png) [@gillesboisson](https://discourse.threejs.org/u/gillesboisson)\
**Post date:** [October 26, 2023, 2:28pm UTC](https://discourse.threejs.org/t/webglcuberendertarget-render-to-a-specific-mipmap-level/57400/4 "2023-10-26T14:28:57Z")

</div>

Thanks,

I didn’t have the last version of three JS, mipmap option was missing from cube camera. I didn’t want to use it as I’m just wrapping cubemaps from 2D texture faces sheet.

Here is my implementation which is quite different from the example use case.

```plaintext
wrapCubeLodFromTexture(
    source: Texture,
    cubeMapSize: number,
    lodLayouts: CubemapWrapperLayout[]
  ) {
    this._material.uniforms.sourceTexture.value = source

    const renderTarget = new WebGLCubeRenderTarget(cubeMapSize, {
      format: source.format,
      type: source.type,
      colorSpace: source.colorSpace,

      ...this.renderTargetOptions,
      
      magFilter: LinearFilter,
      // without setting Mipmap filter creating mipmap files
      minFilter: LinearMipMapLinearFilter,
      generateMipmaps: false,
      depthBuffer: false,
    })

    const camera = new CubeCamera(1, 50, renderTarget)
    const mesh = new Mesh(undefined, this._material)
    

    // no matter how many mipmaps you want to render
    // this has to be setup based on cube size
    // you just to be sure you cubemap is sized enough to match you requirements
    const mipLevels = Math.log(cubeMapSize) * Math.LOG2E + 1.0
    const mipmapCount = Math.floor(
      Math.log2(Math.max(cubeMapSize, cubeMapSize))
    )

   // I coudn't verified in details but most the time mipmapCount = mipLevels - 1

    for (let mip = 0; mip < mipLevels; mip++) {
      // tell three js to prepare storage for rendering
      renderTarget.texture.mipmaps.push({})
    }

    let geom: BufferGeometry
    
    // for each level create a cube with proper uvs to wrap source texture
    for (let lod = 0; lod < mipmapCount; lod++) {
      if (lod < lodLayouts.length) {
        const layout = lodLayouts[lod]
        geom = createCubeWrapperGeom(layout)
        mesh.geometry = geom
      }

      renderTarget.viewport.set(
        0,
        0,
        renderTarget.width >> lod,
        renderTarget.height >> lod
      )
      camera.activeMipmapLevel = lod
      // error in ts definition camera require a scene and not a mesh like the example
      camera.update(this.renderer, mesh as any)

      geom.dispose()
    }

    return renderTarget.texture
  }

```
