algorithm - ¿Convertir números de coma flotante a dígitos decimales en GLSL?
opengl printf (3)
+1 por problema interesante.
Tenía curiosidad, así que intenté codificar esto.
Necesito el uso de matrices, así que elegí
#version 420 core
.
Mi aplicación muestra una pantalla de cobertura cuádruple simple con coordenadas
<-1,+1>
.
Estoy usando la
textura de fuente ASCII 8x8 píxeles 32x8 caracteres
que creé hace algunos años:
El vértice es simple:
//---------------------------------------------------------------------------
// Vertex
//---------------------------------------------------------------------------
#version 420 core
//---------------------------------------------------------------------------
layout(location=0) in vec4 vertex;
out vec2 pos; // screen position <-1,+1>
void main()
{
pos=vertex.xy;
gl_Position=vertex;
}
//---------------------------------------------------------------------------
El fragmento es un poco más complicado:
//---------------------------------------------------------------------------
// Fragment
//---------------------------------------------------------------------------
#version 420 core
//---------------------------------------------------------------------------
in vec2 pos; // screen position <-1,+1>
out vec4 gl_FragColor; // fragment output color
uniform sampler2D txr_font; // ASCII 32x8 characters font texture unit
uniform float fxs,fys; // font/screen resolution ratio
//---------------------------------------------------------------------------
const int _txtsiz=32; // text buffer size
int txt[_txtsiz],txtsiz; // text buffer and its actual size
vec4 col; // color interface for txt_print()
//---------------------------------------------------------------------------
void txt_decimal(float x) // print float x into txt
{
int i,j,c; // l is size of string
float y,a;
const float base=10;
// handle sign
if (x<0.0) { txt[txtsiz]=''-''; txtsiz++; x=-x; }
else { txt[txtsiz]=''+''; txtsiz++; }
// divide to int(x).fract(y) parts of number
y=x; x=floor(x); y-=x;
// handle integer part
i=txtsiz; // start of integer part
for (;txtsiz<_txtsiz;)
{
a=x;
x=floor(x/base);
a-=base*x;
txt[txtsiz]=int(a)+''0''; txtsiz++;
if (x<=0.0) break;
}
j=txtsiz-1; // end of integer part
for (;i<j;i++,j--) // reverse integer digits
{
c=txt[i]; txt[i]=txt[j]; txt[j]=c;
}
// handle fractional part
for (txt[txtsiz]=''.'',txtsiz++;txtsiz<_txtsiz;)
{
y*=base;
a=floor(y);
y-=a;
txt[txtsiz]=int(a)+''0''; txtsiz++;
if (y<=0.0) break;
}
txt[txtsiz]=0; // string terminator
}
//---------------------------------------------------------------------------
void txt_print(float x0,float y0) // print txt at x0,y0 [chars]
{
int i;
float x,y;
// fragment position [chars] relative to x0,y0
x=0.5*(1.0+pos.x)/fxs; x-=x0;
y=0.5*(1.0-pos.y)/fys; y-=y0;
// inside bbox?
if ((x<0.0)||(x>float(txtsiz))||(y<0.0)||(y>1.0)) return;
// get font texture position for target ASCII
i=int(x); // char index in txt
x-=float(i);
i=txt[i];
x+=float(int(i&31));
y+=float(int(i>>5));
x/=32.0; y/=8.0; // offset in char texture
col=texture2D(txr_font,vec2(x,y));
}
//---------------------------------------------------------------------------
void main()
{
col=vec4(0.0,1.0,0.0,1.0); // background color
txtsiz=0;
txt[txtsiz]=''F''; txtsiz++;
txt[txtsiz]=''l''; txtsiz++;
txt[txtsiz]=''o''; txtsiz++;
txt[txtsiz]=''a''; txtsiz++;
txt[txtsiz]=''t''; txtsiz++;
txt[txtsiz]='':''; txtsiz++;
txt[txtsiz]='' ''; txtsiz++;
txt_decimal(12.345);
txt_print(1.0,1.0);
gl_FragColor=col;
}
//---------------------------------------------------------------------------
Aquí mis uniformes laterales de CPU:
glUniform1i(glGetUniformLocation(prog_id,"txr_font"),0);
glUniform1f(glGetUniformLocation(prog_id,"fxs"),(8.0)/float(xs));
glUniform1f(glGetUniformLocation(prog_id,"fys"),(8.0)/float(ys));
donde
xs,ys
es mi resolución de pantalla.
La fuente es 8x8 en la unidad 0
Aquí salida para el código de fragmento de prueba:
Si la precisión de su punto flotante disminuye debido a la implementación de HW, entonces debería considerar imprimir en hexadecimal donde no hay pérdida de precisión (usando acceso binario). Eso podría convertirse en base decadica en enteros más tarde ...
ver:
- conversión de cadena hex2dec en matemática entera
[Edit2] sombreadores GLSL de estilo antiguo
Traté de portar al
GLSL de
estilo antiguo y de repente funciona (antes no se compilaba con las matrices presentes, pero cuando pienso en ello estaba probando
char[]
que era la verdadera razón).
//---------------------------------------------------------------------------
// Vertex
//---------------------------------------------------------------------------
varying vec2 pos; // screen position <-1,+1>
void main()
{
pos=gl_Vertex.xy;
gl_Position=gl_Vertex;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Fragment
//---------------------------------------------------------------------------
varying vec2 pos; // screen position <-1,+1>
uniform sampler2D txr_font; // ASCII 32x8 characters font texture unit
uniform float fxs,fys; // font/screen resolution ratio
//---------------------------------------------------------------------------
const int _txtsiz=32; // text buffer size
int txt[_txtsiz],txtsiz; // text buffer and its actual size
vec4 col; // color interface for txt_print()
//---------------------------------------------------------------------------
void txt_decimal(float x) // print float x into txt
{
int i,j,c; // l is size of string
float y,a;
const float base=10.0;
// handle sign
if (x<0.0) { txt[txtsiz]=''-''; txtsiz++; x=-x; }
else { txt[txtsiz]=''+''; txtsiz++; }
// divide to int(x).fract(y) parts of number
y=x; x=floor(x); y-=x;
// handle integer part
i=txtsiz; // start of integer part
for (;txtsiz<_txtsiz;)
{
a=x;
x=floor(x/base);
a-=base*x;
txt[txtsiz]=int(a)+''0''; txtsiz++;
if (x<=0.0) break;
}
j=txtsiz-1; // end of integer part
for (;i<j;i++,j--) // reverse integer digits
{
c=txt[i]; txt[i]=txt[j]; txt[j]=c;
}
// handle fractional part
for (txt[txtsiz]=''.'',txtsiz++;txtsiz<_txtsiz;)
{
y*=base;
a=floor(y);
y-=a;
txt[txtsiz]=int(a)+''0''; txtsiz++;
if (y<=0.0) break;
}
txt[txtsiz]=0; // string terminator
}
//---------------------------------------------------------------------------
void txt_print(float x0,float y0) // print txt at x0,y0 [chars]
{
int i;
float x,y;
// fragment position [chars] relative to x0,y0
x=0.5*(1.0+pos.x)/fxs; x-=x0;
y=0.5*(1.0-pos.y)/fys; y-=y0;
// inside bbox?
if ((x<0.0)||(x>float(txtsiz))||(y<0.0)||(y>1.0)) return;
// get font texture position for target ASCII
i=int(x); // char index in txt
x-=float(i);
i=txt[i];
x+=float(int(i-((i/32)*32)));
y+=float(int(i/32));
x/=32.0; y/=8.0; // offset in char texture
col=texture2D(txr_font,vec2(x,y));
}
//---------------------------------------------------------------------------
void main()
{
col=vec4(0.0,1.0,0.0,1.0); // background color
txtsiz=0;
txt[txtsiz]=''F''; txtsiz++;
txt[txtsiz]=''l''; txtsiz++;
txt[txtsiz]=''o''; txtsiz++;
txt[txtsiz]=''a''; txtsiz++;
txt[txtsiz]=''t''; txtsiz++;
txt[txtsiz]='':''; txtsiz++;
txt[txtsiz]='' ''; txtsiz++;
txt_decimal(12.345);
txt_print(1.0,1.0);
gl_FragColor=col;
}
//---------------------------------------------------------------------------
Como otros han discutido , GLSL carece de cualquier tipo de depuración de printf. Pero a veces realmente quiero examinar los valores numéricos mientras depuro mis sombreadores.
He estado tratando de crear una herramienta de depuración visual.
Descubrí que es posible renderizar una serie arbitraria de dígitos con bastante facilidad en un sombreador, si trabaja con un
sampler2D
en el que los dígitos
0123456789
se han representado en el monoespacio.
Básicamente, solo haces malabares con tu coordenada x.
Ahora, para usar esto para examinar un número de coma flotante, necesito un algoritmo para convertir un
float
a una secuencia de dígitos decimales, como puede encontrar en cualquier implementación de
printf
.
Desafortunadamente,
hasta donde entiendo el tema,
estos algoritmos parecen necesitar volver a representar el número de coma flotante en un formato de mayor precisión, y no veo cómo esto será posible en GLSL, donde parece que tengo solo
float
32 bits disponibles.
Por esta razón, creo que esta pregunta no es un duplicado de ninguna pregunta general sobre "cómo funciona printf", sino más bien específicamente sobre cómo se puede hacer que estos algoritmos funcionen bajo las restricciones de GLSL.
He visto
esta pregunta y respuesta
, pero no tengo idea de lo que está sucediendo allí.
Los algoritmos que he probado no son muy buenos.
Mi primer intento, marcado como Versión A (comentado), parecía bastante malo: para tomar tres ejemplos aleatorios,
RenderDecimal(1.0)
presentado como
1.099999702
,
RenderDecimal(2.5)
me dio
2.599999246
y
RenderDecimal(2.6)
salió como
2.699999280
.
Mi segundo intento, marcado como Versión B, parecía un poco mejor:
1.0
y
2.6
salen bien, pero
RenderDecimal(2.5)
todavía no coincide con un redondeo aparente de los
5
con el hecho de que el residual es
0.099...
El resultado aparece como
2.599000022
.
Mi ejemplo mínimo / completo / verificable, a continuación, comienza con un breve código GLSL 1.20, y luego he elegido Python 2.x para el resto, solo para compilar los sombreadores y cargar y renderizar las texturas.
Requiere los paquetes de terceros pygame, numpy, PyOpenGL y PIL.
Tenga en cuenta que Python es en realidad una plantilla repetitiva y podría reescribirse trivialmente (aunque tediosamente) en C o cualquier otra cosa.
Solo el código GLSL en la parte superior es crítico para esta pregunta, y por esta razón no creo que las etiquetas
python
o
python 2.x
sean útiles.
Requiere que la siguiente imagen se guarde como
digits.png
:
vertexShaderSource = """/
varying vec2 vFragCoordinate;
void main(void)
{
vFragCoordinate = gl_Vertex.xy;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
"""
fragmentShaderSource = """/
varying vec2 vFragCoordinate;
uniform vec2 uTextureSize;
uniform sampler2D uTextureSlotNumber;
float OrderOfMagnitude( float x )
{
return x == 0.0 ? 0.0 : floor( log( abs( x ) ) / log( 10.0 ) );
}
void RenderDecimal( float value )
{
// Assume that the texture to which uTextureSlotNumber refers contains
// a rendering of the digits ''0123456789'' packed together, such that
const vec2 startOfDigitsInTexture = vec2( 0, 0 ); // the lower-left corner of the first digit starts here and
const vec2 sizeOfDigit = vec2( 100, 125 ); // each digit spans this many pixels
const float nSpaces = 10.0; // assume we have this many digits'' worth of space to render in
value = abs( value );
vec2 pos = vFragCoordinate - startOfDigitsInTexture;
float dpstart = max( 0.0, OrderOfMagnitude( value ) );
float decimal_position = dpstart - floor( pos.x / sizeOfDigit.x );
float remainder = mod( pos.x, sizeOfDigit.x );
if( pos.x >= 0 && pos.x < sizeOfDigit.x * nSpaces && pos.y >= 0 && pos.y < sizeOfDigit.y )
{
float digit_value;
// Version B
float dp, running_value = value;
for( dp = dpstart; dp >= decimal_position; dp -= 1.0 )
{
float base = pow( 10.0, dp );
digit_value = mod( floor( running_value / base ), 10.0 );
running_value -= digit_value * base;
}
// Version A
//digit_value = mod( floor( value * pow( 10.0, -decimal_position ) ), 10.0 );
vec2 textureSourcePosition = vec2( startOfDigitsInTexture.x + remainder + digit_value * sizeOfDigit.x, startOfDigitsInTexture.y + pos.y );
gl_FragColor = texture2D( uTextureSlotNumber, textureSourcePosition / uTextureSize );
}
// Render the decimal point
if( ( decimal_position == -1.0 && remainder / sizeOfDigit.x < 0.1 && abs( pos.y ) / sizeOfDigit.y < 0.1 ) ||
( decimal_position == 0.0 && remainder / sizeOfDigit.x > 0.9 && abs( pos.y ) / sizeOfDigit.y < 0.1 ) )
{
gl_FragColor = texture2D( uTextureSlotNumber, ( startOfDigitsInTexture + sizeOfDigit * vec2( 1.5, 0.5 ) ) / uTextureSize );
}
}
void main(void)
{
gl_FragColor = texture2D( uTextureSlotNumber, vFragCoordinate / uTextureSize );
RenderDecimal( 2.5 ); // for current demonstration purposes, just a constant
}
"""
# Python (PyOpenGL) code to demonstrate the above
# (Note: the same OpenGL calls could be made from any language)
import os, sys, time
import OpenGL
from OpenGL.GL import *
from OpenGL.GLU import *
import pygame, pygame.locals # just for getting a canvas to draw on
try: from PIL import Image # PIL.Image module for loading image from disk
except ImportError: import Image # old PIL didn''t package its submodules on the path
import numpy # for manipulating pixel values on the Python side
def CompileShader( type, source ):
shader = glCreateShader( type )
glShaderSource( shader, source )
glCompileShader( shader )
result = glGetShaderiv( shader, GL_COMPILE_STATUS )
if result != 1:
raise Exception( "Shader compilation failed:/n" + glGetShaderInfoLog( shader ) )
return shader
class World:
def __init__( self, width, height ):
self.window = pygame.display.set_mode( ( width, height ), pygame.OPENGL | pygame.DOUBLEBUF )
# compile shaders
vertexShader = CompileShader( GL_VERTEX_SHADER, vertexShaderSource )
fragmentShader = CompileShader( GL_FRAGMENT_SHADER, fragmentShaderSource )
# build shader program
self.program = glCreateProgram()
glAttachShader( self.program, vertexShader )
glAttachShader( self.program, fragmentShader )
glLinkProgram( self.program )
# try to activate/enable shader program, handling errors wisely
try:
glUseProgram( self.program )
except OpenGL.error.GLError:
print( glGetProgramInfoLog( self.program ) )
raise
# enable alpha blending
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE )
glEnable( GL_DEPTH_TEST )
glEnable( GL_BLEND )
glBlendEquation( GL_FUNC_ADD )
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA )
# set projection and background color
gluOrtho2D( 0, width, 0, height )
glClearColor( 0.0, 0.0, 0.0, 1.0 )
self.uTextureSlotNumber_addr = glGetUniformLocation( self.program, ''uTextureSlotNumber'' )
self.uTextureSize_addr = glGetUniformLocation( self.program, ''uTextureSize'' )
def RenderFrame( self, *textures ):
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
for t in textures: t.Draw( world=self )
pygame.display.flip()
def Close( self ):
pygame.display.quit()
def Capture( self ):
w, h = self.window.get_size()
rawRGB = glReadPixels( 0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE )
return Image.frombuffer( ''RGB'', ( w, h ), rawRGB, ''raw'', ''RGB'', 0, 1 ).transpose( Image.FLIP_TOP_BOTTOM )
class Texture:
def __init__( self, source, slot=0, position=(0,0,0) ):
# wrangle array
source = numpy.array( source )
if source.dtype.type not in [ numpy.float32, numpy.float64 ]: source = source.astype( float ) / 255.0
while source.ndim < 3: source = numpy.expand_dims( source, -1 )
if source.shape[ 2 ] == 1: source = source[ :, :, [ 0, 0, 0 ] ] # LUMINANCE -> RGB
if source.shape[ 2 ] == 2: source = source[ :, :, [ 0, 0, 0, 1 ] ] # LUMINANCE_ALPHA -> RGBA
if source.shape[ 2 ] == 3: source = source[ :, :, [ 0, 1, 2, 2 ] ]; source[ :, :, 3 ] = 1.0 # RGB -> RGBA
# now it can be transferred as GL_RGBA and GL_FLOAT
# housekeeping
self.textureSize = [ source.shape[ 1 ], source.shape[ 0 ] ]
self.textureSlotNumber = slot
self.textureSlotCode = getattr( OpenGL.GL, ''GL_TEXTURE%d'' % slot )
self.listNumber = slot + 1
self.position = list( position )
# transfer texture content
glActiveTexture( self.textureSlotCode )
self.textureID = glGenTextures( 1 )
glBindTexture( GL_TEXTURE_2D, self.textureID )
glEnable( GL_TEXTURE_2D )
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA32F, self.textureSize[ 0 ], self.textureSize[ 1 ], 0, GL_RGBA, GL_FLOAT, source[ ::-1 ] )
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST )
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST )
# define surface
w, h = self.textureSize
glNewList( self.listNumber, GL_COMPILE )
glBegin( GL_QUADS )
glColor3f( 1, 1, 1 )
glNormal3f( 0, 0, 1 )
glVertex3f( 0, h, 0 )
glVertex3f( w, h, 0 )
glVertex3f( w, 0, 0 )
glVertex3f( 0, 0, 0 )
glEnd()
glEndList()
def Draw( self, world ):
glPushMatrix()
glTranslate( *self.position )
glUniform1i( world.uTextureSlotNumber_addr, self.textureSlotNumber )
glUniform2f( world.uTextureSize_addr, *self.textureSize )
glCallList( self.listNumber )
glPopMatrix()
world = World( 1000, 800 )
digits = Texture( Image.open( ''digits.png'' ) )
done = False
while not done:
world.RenderFrame( digits )
for event in pygame.event.get():
# Press ''q'' to quit or ''s'' to save a timestamped snapshot
if event.type == pygame.locals.QUIT: done = True
elif event.type == pygame.locals.KEYUP and event.key in [ ord( ''q'' ), 27 ]: done = True
elif event.type == pygame.locals.KEYUP and event.key in [ ord( ''s'' ) ]:
world.Capture().save( time.strftime( ''snapshot-%Y%m%d-%H%M%S.png'' ) )
world.Close()
Aquí está mi sombreador de fragmentos actualizado, que se puede colocar en la lista de mi pregunta original. Implementa el algoritmo de búsqueda de dígitos decimales que Spektre propuso, de una manera que incluso es compatible con el dialecto GLSL 1.20 heredado que estoy usando. Sin esa restricción, la solución de Spektre es, por supuesto, mucho más elegante y poderosa.
varying vec2 vFragCoordinate;
uniform vec2 uTextureSize;
uniform sampler2D uTextureSlotNumber;
float Digit( float x, int position, float base )
{
int i;
float digit;
if( position < 0 )
{
x = fract( x );
for( i = -1; i >= position; i-- )
{
if( x <= 0.0 ) { digit = 0.0; break; }
x *= base;
digit = floor( x );
x -= digit;
}
}
else
{
x = floor( x );
float prevx;
for( i = 0; i <= position; i++ )
{
if( x <= 0.0 ) { digit = 0.0; break; }
prevx = x;
x = floor( x / base );
digit = prevx - base * x;
}
}
return digit;
}
float OrderOfMagnitude( float x )
{
return x == 0.0 ? 0.0 : floor( log( abs( x ) ) / log( 10.0 ) );
}
void RenderDecimal( float value )
{
// Assume that the texture to which uTextureSlotNumber refers contains
// a rendering of the digits ''0123456789'' packed together, such that
const vec2 startOfDigitsInTexture = vec2( 0, 0 ); // the lower-left corner of the first digit starts here and
const vec2 sizeOfDigit = vec2( 100, 125 ); // each digit spans this many pixels
const float nSpaces = 10.0; // assume we have this many digits'' worth of space to render in
value = abs( value );
vec2 pos = vFragCoordinate - startOfDigitsInTexture;
float dpstart = max( 0.0, OrderOfMagnitude( value ) );
int decimal_position = int( dpstart - floor( pos.x / sizeOfDigit.x ) );
float remainder = mod( pos.x, sizeOfDigit.x );
if( pos.x >= 0.0 && pos.x < sizeOfDigit.x * nSpaces && pos.y >= 0.0 && pos.y < sizeOfDigit.y )
{
float digit_value = Digit( value, decimal_position, 10.0 );
vec2 textureSourcePosition = vec2( startOfDigitsInTexture.x + remainder + digit_value * sizeOfDigit.x, startOfDigitsInTexture.y + pos.y );
gl_FragColor = texture2D( uTextureSlotNumber, textureSourcePosition / uTextureSize );
}
// Render the decimal point
if( ( decimal_position == -1 && remainder / sizeOfDigit.x < 0.1 && abs( pos.y ) / sizeOfDigit.y < 0.1 ) ||
( decimal_position == 0 && remainder / sizeOfDigit.x > 0.9 && abs( pos.y ) / sizeOfDigit.y < 0.1 ) )
{
gl_FragColor = texture2D( uTextureSlotNumber, ( startOfDigitsInTexture + sizeOfDigit * vec2( 1.5, 0.5 ) ) / uTextureSize );
}
}
void main(void)
{
gl_FragColor = texture2D( uTextureSlotNumber, vFragCoordinate / uTextureSize );
RenderDecimal( 2.5 ); // for current demonstration purposes, just a constant
}
En primer lugar, quiero mencionar que la increíble solución de Spektre es casi perfecta y aún más una solución general para la salida de texto. Le di una respuesta a su respuesta. Como alternativa, presento una solución mínimamente invasiva y mejoro el código de la pregunta.
No quiero ocultar el hecho de que he estudiado la solución de Spektre y me he integrado a mi solución.
// Assume that the texture to which uTextureSlotNumber refers contains
// a rendering of the digits ''0123456789'' packed together, such that
const vec2 startOfDigitsInTexture = vec2( 100, 125 ); // the lower-left corner of the first digit starts here and
const vec2 sizeOfDigit = vec2( 0.1, 0.2 ); // each digit spans this many pixels
const float nSpaces = 10.0; // assume we have this many digits'' worth of space to render in
void RenderDigit( int strPos, int digit, vec2 pos )
{
float testStrPos = pos.x / sizeOfDigit.x;
if ( testStrPos >= float(strPos) && testStrPos < float(strPos+1) )
{
float start = sizeOfDigit.x * float(digit);
vec2 textureSourcePosition = vec2( startOfDigitsInTexture.x + start + mod( pos.x, sizeOfDigit.x ), startOfDigitsInTexture.y + pos.y );
gl_FragColor = texture2D( uTextureSlotNumber, textureSourcePosition / uTextureSize );
}
}
La función
ValueToDigits
interpreta un número de coma flotante y llena una matriz con los dígitos.
Cada número en la matriz está en (
0
,
9
).
const int MAX_DIGITS = 32;
int digits[MAX_DIGITS];
int noOfDigits = 0;
int posOfComma = 0;
void Reverse( int start, int end )
{
for ( ; start < end; ++ start, -- end )
{
int digit = digits[start];
digits[start] = digits[end];
digits[end] = digit;
}
}
void ValueToDigits( float value )
{
const float base = 10.0;
int start = noOfDigits;
value = abs( value );
float frac = value; value = floor(value); frac -= value;
// integral digits
for ( ; value > 0.0 && noOfDigits < MAX_DIGITS; ++ noOfDigits )
{
float newValue = floor( value / base );
digits[noOfDigits] = int( value - base * newValue );
value = newValue;
}
Reverse( start, noOfDigits-1 );
posOfComma = noOfDigits;
// fractional digits
for ( ; frac > 0.0 && noOfDigits < MAX_DIGITS; ++ noOfDigits )
{
frac *= base;
float digit = floor( frac );
frac -= digit;
digits[noOfDigits] = int( digit );
}
}
Llame a
ValueToDigits
en su función original y encuentre las coordenadas de dígitos y texturas para el fragmento actual.
void RenderDecimal( float value )
{
// fill the array of digits with the floating point value
ValueToDigits( value );
// Render the digits
vec2 pos = vFragCoordinate.xy - startOfDigitsInTexture;
if( pos.x >= 0 && pos.x < sizeOfDigit.x * nSpaces && pos.y >= 0 && pos.y < sizeOfDigit.y )
{
// render the digits
for ( int strPos = 0; strPos < noOfDigits; ++ strPos )
RenderDigit( strPos, digits[strPos], pos );
}
// Render the decimal point
float testStrPos = pos.x / sizeOfDigit.x;
float remainder = mod( pos.x, sizeOfDigit.x );
if( ( testStrPos >= float(posOfComma) && testStrPos < float(posOfComma+1) && remainder / sizeOfDigit.x < 0.1 && abs( pos.y ) / sizeOfDigit.y < 0.1 ) ||
( testStrPos >= float(posOfComma-1) && testStrPos < float(posOfComma) && remainder / sizeOfDigit.x > 0.9 && abs( pos.y ) / sizeOfDigit.y < 0.1 ) )
{
gl_FragColor = texture2D( uTextureSlotNumber, ( startOfDigitsInTexture + sizeOfDigit * vec2( 1.5, 0.5 ) ) / uTextureSize );
}
}