2015-05-07 2 views
7

У меня есть текстуры Float32Array, которые могут отображаться через WebGL правильно. Однако, когда я пытался преобразовать их в Uint16Array, проблема возникает.Преобразование из Float32Array в Uint16Array в WebGL

enter image description here

Вот мое преобразование часть.

var _floatToHalfFloat = function(input, offset) { 
    var largestHalf = Math.pow(2, 30-15) * (1 + 1023/1024); 
    var m = new ArrayBuffer(4); 
    var n = new Float32Array(m); 
    var o = new Uint32Array(m); 
    var f = 0.0; 
    for (var i = input.length - 1 - offset; i >= 0;i--) { 
     n[0] = input[i]; 
     f = o[0]; 
     // fast conversion of half 
     // ref : ftp://www.fox-toolkit.org/pub/fasthalffloatconversion.pdf 

     if (isNaN(input[i])) { 
      input[i] = 0x7fff; 
     } else if(n === Infinity || n > largestHalf) { 
      input[i] = 0x7c00; 
     } else if(n === -Infinity || n < -largestHalf) { 
      input[i] = 0xfc00; 
     } else if(n === 0) { 
      input[i] = 0; 
     } else { 
      input[i] = ((f>>16)&0x8000)|((((f&0x7f800000)-0x38000000)>>13)&0x7c00)|((f>>13)&0x03ff); 
     } 
    } 
    return new Uint16Array(input); 
}; 

ответ

1

Мы можем видеть насыщенные цвета (полный красный, зеленый и/или синий) в преобразованном изображении при достижении черного цвета в исходном изображении. Я думаю, что функция не работает очень хорошо рядом с 0.

Я сделал быструю реализацию wikipedia explanation of norm of the float 16 bits.

<html> 
<head> 
<script> 
var _floatToHalfFloat = #### YOUR FUNCTION HERE CUT #### 

var _halfFloatToFloat = function(hf) { 
    var m = new ArrayBuffer(2); 
    var n = new Uint16Array(m); 
    n[0] = hf; 
    var sign = n[0] & 0x8000; 
    var exp = (n[0] >> 10) & 0x1F; 
    var mant = n[0]& 0x03FF; 
    document.getElementById('sign').innerHTML += sign+" - "; 
    document.getElementById('exp').innerHTML += exp+" - "; 
    document.getElementById('mant').innerHTML += mant+" - "; 
    if (exp == 0x1F) { 
    return 1.0 * Math.pow(-1, sign) * Infinity; 
    } else if (exp == 0) { 
    return Math.pow(-1, sign) * 
      Math.pow(2, -14) * 
      (mant/Math.pow(2, 10)); 
    } else { 
    return Math.pow(-1, sign) * 
      Math.pow(2, exp-15) * 
      (1+(mant/Math.pow(2, 10))); 
    } 
}; 

document.addEventListener("DOMContentLoaded", function(event) { 
    var input = new Float32Array(8); 
    input[0] = 2.5; 
    input[1] = 0.25; 
    input[2] = 0.025; 
    input[3] = 0.025; 
    input[4] = 0.0025; 
    input[5] = 0.00025; 
    input[6] = 0.000025; 
    input[7] = 0.0; 

    var i, s = "Value before = "; 
    for (i = 0; i < input.length; i++) 
    s += input[i] + " - "; 
    document.getElementById('res1').innerHTML = s; 
    var output = _floatToHalfFloat(input, 0); 
    s = "Value after = "; 
    for (i = 0; i < output.length; i++) 
    s += _halfFloatToFloat(output[i]) + " - "; 
    document.getElementById('res2').innerHTML = s; 
}); 
</script> 
</head> 
<body> 
    <span id="res1">result</span></br> 
    <span id="res2">result</span></br> 
    </br></br></br> 
    <span id="sign">signs =</span></br> 
    <span id="exp">exponents =</span></br> 
    <span id="mant">mantissas =</span></br> 
</body> 
</html> 

Результаты испытаний приведены ниже:

Value before = 2.5 - 0.25 - 0.02500000037252903 - 0.02500000037252903 - 0.0024999999441206455 - 0.0002500000118743628 - 0.00002499999936844688 - 0 - 
Value after = 2.5 - 0.25 - 0.024993896484375 - 0.024993896484375 - 0.002498626708984375 - 0.0002498626708984375 - Infinity - 2 - 



signs =0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 
exponents =16 - 13 - 9 - 9 - 6 - 3 - 31 - 16 - 
mantissas =256 - 0 - 614 - 614 - 286 - 24 - 653 - 0 - 

Это показывает, что 2 последняя информация не является когерентной. 0,000025 преобразуется в Бесконечность (а не 0?), А само само преобразуется в 2. Это не кажется правильным. Когда вы хотите закодировать нуль, «википедия говорит», ваша мантисса И ваш показатель должен быть равен нулю. В коде, который вы указали, мантисса равна нулю, а показатель составляет 16, что приводит к 2 (2^(16-15)).

После некоторой настройки вашей функции кажется, что все случаи рассматриваются как обычные. Это связано с ошибкой в ​​ваших операторах if. Поэтому вместо того, чтобы:

} else if(n === 0) { 
    input[i] = 0; 
} 

Вы хотите, вероятно, сделать что-то вроде этого:

} else if(n[0] === 0) { 
    input[i] = 0; 
} 

И то же самое для всех видов использования n переменной. Но у вас все еще есть проблема с переполнением. Возможно, вы можете найти приемлемый вариант:

} else if(Math.abs(n[0]) < 0.0001) { 
    input[i] = 0; 
}