2015-05-07 4 views
7

Ich habe Float32Array Texturen, die über WebGL korrekt angezeigt werden können. Als ich jedoch versuchte, sie in Uint16Array umzuwandeln, tritt das Problem auf.Konvertierung von Float32Array zu Uint16Array in WebGL

enter image description here

Hier ist mein Umwandlungsteil.

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); 
}; 

Antwort

1

Wir können gesättigte Farben (voll rot, grün und/oder blau) im konvertierten Bild sehen, wenn im Originalbild schwarze Farbe erreicht wird. Ich denke, dass die Funktion nicht sehr gut in der Nähe von 0.

funktioniert ich eine schnelle Implementierung von 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> 

Die Testergebnisse sind unten getan haben gezeigt:

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 - 

Dies zeigt, dass die 2 letzte Informationen sind nicht kohärent. 0.000025 wird in Infinity umgewandelt (anstatt 0?) Und 0 selbst wird in 2 umgewandelt. Dies scheint nicht korrekt zu sein. Wenn du eine Null kodieren willst, sagt "Wikipedia sagt" deine Mantisse UND dein Exponent sollte Null sein. In dem von Ihnen angegebenen Code ist die Mantisse Null, aber der Exponent ist 16, was zu 2 führt (2^(16-15)).

Nach ein wenig Ihre Funktion scheint es, dass alle Fälle als normal behandelt werden. Dies liegt an einem Fehler in Ihren if-Anweisungen. Anstatt also mit:

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

Sie wollen wahrscheinlich etwas tun, wie folgt aus:

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

Und das gleiche gilt für alle Verwendungen von n variabel. Aber Sie haben immer noch die Unterlauf Problem.So möglicherweise Sie finden können, akzeptabel zu tun:

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