Skip to content

Commit f4cf0fd

Browse files
Donovan Hutchencewilleastcott
authored andcommitted
generate prefiltered cubemaps with full mip chain, patch textures with partial mip chains (playcanvas#1580)
1 parent 56ec8d0 commit f4cf0fd

File tree

2 files changed

+46
-30
lines changed

2 files changed

+46
-30
lines changed

src/graphics/device.js

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,43 @@ Object.assign(pc, function () {
15111511
}
15121512
},
15131513

1514+
// In the case where a texture has more than 1 level of mip data specified, but doesn't have
1515+
// the full mip chain, we generate the missing levels here.
1516+
// This is to overcome an issue where iphone xr and xs ignores further updates to the mip data
1517+
// after invoking gl.generateMipmap on the texture (which was the previous method of ensuring
1518+
// the texture's full mip chain was complete).
1519+
// NOTE: this function copies texture data from the previous mip level instead of downsampling it.
1520+
_completePartialMipmapChain: function (texture) {
1521+
1522+
var requiredMipLevels = Math.log2(Math.max(texture._width, texture._height)) + 1;
1523+
1524+
if (texture._levels.length === 1 ||
1525+
texture._levels.length === requiredMipLevels ||
1526+
!(texture._levels[0] instanceof Array) ||
1527+
texture._compressed ||
1528+
texture._volume) {
1529+
return;
1530+
}
1531+
1532+
// step through levels
1533+
var elementsPerPixel = (texture._cubemap ? texture._levels[0][0] : texture._levels[0]).length / (texture._width * texture._height);
1534+
for (var level = texture._levels.length; level < requiredMipLevels; ++level) {
1535+
var width = Math.max(1, texture._width >> level);
1536+
var height = Math.max(1, texture._height >> level);
1537+
var size = Math.floor(width * height * elementsPerPixel);
1538+
if (texture._cubemap) {
1539+
var mips = [];
1540+
for (var face = 0; face < 6; ++face) {
1541+
mips.push(texture._levels[level - 1][face].subarray(0, size));
1542+
}
1543+
texture._levels.push(mips);
1544+
} else {
1545+
texture._levels.push(texture._levels[level - 1].subarray(0, size));
1546+
}
1547+
}
1548+
texture._levelsUpdated = texture._cubemap ? [[true, true, true, true, true, true]] : [true];
1549+
},
1550+
15141551
uploadTexture: function (texture) {
15151552
var gl = this.gl;
15161553

@@ -1521,6 +1558,8 @@ Object.assign(pc, function () {
15211558
var mipObject;
15221559
var resMult;
15231560

1561+
this._completePartialMipmapChain(texture);
1562+
15241563
while (texture._levels[mipLevel] || mipLevel === 0) {
15251564
// Upload all existing mip levels. Initialize 0 mip anyway.
15261565

@@ -1533,13 +1572,6 @@ Object.assign(pc, function () {
15331572

15341573
mipObject = texture._levels[mipLevel];
15351574

1536-
if (mipLevel == 1 && !texture._compressed) {
1537-
// We have more than one mip levels we want to assign, but we need all mips to make
1538-
// the texture complete. Therefore first generate all mip chain from 0, then assign custom mips.
1539-
gl.generateMipmap(texture._glTarget);
1540-
texture._mipmapsUploaded = true;
1541-
}
1542-
15431575
if (texture._cubemap) {
15441576
// ----- CUBEMAP -----
15451577
var face;

src/graphics/prefilter-cubemap.js

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ Object.assign(pc, (function () {
4141
var format = sourceCubemap.format;
4242

4343
var cmapsList = [[], options.filteredFixed, options.filteredRgbm, options.filteredFixedRgbm];
44-
var gloss = method === 0 ? [0.9, 0.85, 0.7, 0.4, 0.25] : [512, 128, 32, 8, 2]; // TODO: calc more correct values depending on mip
45-
var mipSize = [64, 32, 16, 8, 4]; // TODO: make non-static?
46-
var numMips = 5;
44+
var gloss = method === 0 ? [0.9, 0.85, 0.7, 0.4, 0.25, 0.15, 0.1] : [512, 128, 32, 8, 2, 1, 1]; // TODO: calc more correct values depending on mip
45+
var mipSize = [64, 32, 16, 8, 4, 2, 1]; // TODO: make non-static?
46+
var numMips = 7; // generate all mips down to 1x1
4747
var targ;
4848
var i, face, pass;
4949

@@ -207,15 +207,7 @@ Object.assign(pc, (function () {
207207

208208
var mips;
209209
if (cpuSync && options.singleFilteredFixed) {
210-
mips = [
211-
sourceCubemap,
212-
options.filteredFixed[0],
213-
options.filteredFixed[1],
214-
options.filteredFixed[2],
215-
options.filteredFixed[3],
216-
options.filteredFixed[4],
217-
options.filteredFixed[5]
218-
];
210+
mips = [sourceCubemap].concat(options.filteredFixed);
219211
cubemap = new pc.Texture(device, {
220212
cubemap: true,
221213
rgbm: rgbmSource,
@@ -227,7 +219,7 @@ Object.assign(pc, (function () {
227219
addressV: pc.ADDRESS_CLAMP_TO_EDGE
228220
});
229221
cubemap.name = 'prefiltered-cube';
230-
for (i = 0; i < 6; i++)
222+
for (i = 0; i < mips.length; i++)
231223
cubemap._levels[i] = mips[i]._levels[0];
232224

233225
cubemap.upload();
@@ -236,15 +228,7 @@ Object.assign(pc, (function () {
236228
}
237229

238230
if (cpuSync && options.singleFilteredFixedRgbm && options.filteredFixedRgbm) {
239-
mips = [
240-
sourceCubemapRgbm,
241-
options.filteredFixedRgbm[0],
242-
options.filteredFixedRgbm[1],
243-
options.filteredFixedRgbm[2],
244-
options.filteredFixedRgbm[3],
245-
options.filteredFixedRgbm[4],
246-
options.filteredFixedRgbm[5]
247-
];
231+
mips = [sourceCubemapRgbm].concat(options.filteredFixedRgbm);
248232
cubemap = new pc.Texture(device, {
249233
cubemap: true,
250234
rgbm: true,
@@ -256,7 +240,7 @@ Object.assign(pc, (function () {
256240
addressV: pc.ADDRESS_CLAMP_TO_EDGE
257241
});
258242
cubemap.name = 'prefiltered-cube';
259-
for (i = 0; i < 6; i++) {
243+
for (i = 0; i < mips.length; i++) {
260244
cubemap._levels[i] = mips[i]._levels[0];
261245
}
262246
cubemap.upload();

0 commit comments

Comments
 (0)