2017-06-28 15 views
8

As others have discussed, जीएलएसएल में किसी भी प्रकार की प्रिंटफ डिबगिंग की कमी है। लेकिन कभी-कभी मैं वास्तव में अपने शेडर्स को डीबग करते समय संख्यात्मक मानों की जांच करना चाहता हूं।जीएलएसएल में फ्लोटिंग-पॉइंट संख्याओं को दशमलव अंकों में कनवर्ट करें?

मैं एक दृश्य डिबगिंग टूल बनाने की कोशिश कर रहा हूं। मैंने पाया कि यदि आप sampler2D के साथ काम करते हैं तो अंक को मोनोस्पेस में प्रस्तुत किया गया है, तो एक संख्या में आसानी से आसानी से अंकों की मनमानी श्रृंखला प्रस्तुत करना संभव है। असल में, आप बस अपने एक्स समन्वय को जोड़ते हैं।

अब, यह उपयोग करने के लिए एक फ्लोटिंग प्वाइंट नंबर की जांच करने, मैं एक एल्गोरिथ्म दशमलव अंक के अनुक्रम, जैसे आप किसी भी printf कार्यान्वयन में मिल सकती है के लिए एक float परिवर्तित करने के लिए की जरूरत है। दुर्भाग्यवश, as far as I understand the topic इन एल्गोरिदम को फ्लोटिंग-पॉइंट नंबर को उच्च-परिशुद्धता प्रारूप में फिर से प्रस्तुत करने की आवश्यकता प्रतीत होती है, और मुझे नहीं लगता कि यह जीएलएसएल में संभव है जहां मुझे लगता है कि केवल 32- बिट float एस उपलब्ध है। इस कारण से, मुझे लगता है कि यह प्रश्न किसी भी सामान्य "प्रिंटफ काम कैसे करता है" प्रश्न का डुप्लिकेट नहीं है, बल्कि विशेष रूप से इस तरह के एल्गोरिदम को जीएलएसएल की बाधाओं के तहत काम करने के लिए कैसे बनाया जा सकता है। मैंने this question and answer देखा है, लेकिन मुझे पता नहीं है कि वहां क्या हो रहा है।

मैंने कोशिश की एल्गोरिदम बहुत अच्छी नहीं हैं। मेरी पहली कोशिश, चिह्नित संस्करण एक (बाहर टिप्पणी की) बहुत बुरा लग रहा था: तीन यादृच्छिक उदाहरण, RenderDecimal(1.0)1.099999702 के रूप में प्रदान लेने के लिए, RenderDecimal(2.5) मुझे 2.599999246 दिया और RenderDecimal(2.6)2.699999280 के रूप में बाहर आया था। मेरी दूसरी कोशिश, संस्करण बी चिह्नित, लग रहा था थोड़ा बेहतर: 1.0 और 2.6 दोनों ठीक बाहर आते हैं, लेकिन अभी भी RenderDecimal(2.5) एक स्पष्ट 5 के तथ्य यह है कि अवशिष्ट 0.099... है साथ गोलाई-अप बेमेल। परिणाम 2.599000022 के रूप में प्रकट होता है।

मेरे कम से कम/पूर्ण/निरीक्षण उदाहरण के लिए, नीचे, कुछ जरा सा GLSL 1.20 कोड के साथ शुरू होता है, और फिर मैं आराम के लिए पायथन 2.x को चुना है के लिए हो, बस shaders संकलित और बनावट लोड पाने के लिए और प्रदान की गई। इसके लिए पायगम, numpy, PyOpenGL और पीआईएल तीसरे पक्ष पैकेज की आवश्यकता है। ध्यान दें कि पायथन वास्तव में सिर्फ बॉयलरप्लेट है और सी या कुछ और में को फिर से लिखा जा सकता है (हालांकि थकाऊ)। इस प्रश्न के लिए शीर्ष पर केवल जीएलएसएल कोड महत्वपूर्ण है, और इस कारण के लिए मुझे नहीं लगता कि python या python 2.x टैग सहायक होंगे। दिलचस्प समस्या के लिए

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 '' 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() 

उत्तर

10

+1:

यह निम्न छवि digits.png के रूप में सहेजना होगा। उत्सुक था इसलिए मैंने इसे कोड करने की कोशिश की। मुझे सरणी के उपयोग की ज़रूरत है इसलिए मैंने #version 420 core चुना। मेरा ऐप समन्वय <-1,+1> के साथ एकल क्वाड कवर स्क्रीन प्रस्तुत कर रहा है।मैं ASCII 8x8 पिक्सेल 32x8 पात्रों फ़ॉन्ट बनावट पूरे उपयोग कर रहा हूँ मैं कुछ साल पहले बनाया:

font

शिखर सरल है:

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

टुकड़ा थोड़ा अधिक जटिल है:

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

यहाँ मेरी सीपीयू पक्ष वर्दी:

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

जहां xs,ys अपनी स्क्रीन संकल्प है। फ़ॉन्ट परीक्षण टुकड़ा कोड के लिए उत्पादन इकाई में 8x8 0

यहाँ है:

screenshot

अपने चल बिन्दु सटीकता HW कार्यान्वयन की वजह से कम हो जाती है, तो आप हेक्स में मुद्रण जहां कोई सटीकता पर विचार करना चाहिए नुकसान मौजूद है (बाइनरी एक्सेस का उपयोग कर)। यही कारण है कि बाद में पूर्णांकों पर decadic आधार के लिए परिवर्तित किया जा सकता है ...

देखें:

[EDIT2] पुरानी शैली GLSL shaders

मैं करने के लिए बंदरगाह की कोशिश की पुरानी शैली जीएलएसएल और अचानक यह काम करता है (इससे पहले कि यह एरे के साथ संकलित नहीं होगा, लेकिन जब मैं इसके बारे में सोचता हूं तो मैंकी कोशिश कर रहा थाजो वास्तविक कारण था)।

//--------------------------------------------------------------------------- 
// 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; 
    } 
//--------------------------------------------------------------------------- 
+1

फैंसी रेट्रो फ़ॉन्ट के लिए दूसरी बार ऊपर उठ जाएगा! – HolyBlackCat

+0

यह प्रभावशाली काम है! धन्यवाद! किसी कारण से, हालांकि मेरी मशीनों में से एक में जीएलएसएल> 4.20 (वास्तव में 4.30) है, इसके कंपाइलर अक्षर अक्षर जैसे '' '' ('कहते हैं' 'त्रुटि: 0:22:' ': अवैध चरित्र (') (0x27) ')। तो मुझे इन्हें पूरे पूर्णांक अक्षरों के साथ प्रतिस्थापित करना पड़ा, लेकिन फिर मैं यह काम करने में सक्षम था। बहुत ही शांत! मुझे यह उल्लेख करना चाहिए था कि मैं वास्तव में 1.20 तक जीएलएसएल संस्करणों का समर्थन करने में सक्षम होना चाहता हूं लेकिन यह आपके समाधान से अलग नहीं होना चाहिए, विशेष रूप से मूल दशमलवकरण एल्गोरिदम ऐसा लगता है कि यह पोर्टेबल भी होना चाहिए। – jez

+0

इसके अलावा: मैं बाइनरी में प्रतिपादन के बारे में अपना मुद्दा लेता हूं और इसके बजाय खुशी से ऐसा करता हूं, क्योंकि यह ऑन-ऑफ पिक्सेल के अनुक्रम के डीकोडिंग के बाद स्क्रीन कैप्चर को स्वचालित करने के लिए पर्याप्त आसान होना चाहिए। यह वास्तव में एक अधिक उपयोगी सामान्य उद्देश्य समाधान हो सकता है। लेकिन क्या मैं इसे जीएलएसएल संस्करणों में भी कर सकता हूं? मैं 'FloatBitsToUint' के बारे में जानता हूं लेकिन यह केवल 3.30+ संस्करण में उपलब्ध है। जब आपने "बाइनरी एक्सेस" के बारे में बात की थी, तो क्या आपके मन में अन्य कार्य हैं, और यदि ऐसा होगा तो वे विरासत प्रणाली पर उपलब्ध होंगे? यह एक अलग अलग सवाल है जो मुझे लगता है ... – jez

3

सब मुझे लगता है कि Spektre का अद्भुत समाधान लगभग पूर्ण है और उससे भी ज्यादा पाठ उत्पादन के लिए एक सामान्य समाधान उल्लेख करना चाहते हैं पहले। मैंने उसका जवाब अपवोट दिया। एक विकल्प के रूप में, मैं एक न्यूनतम आक्रमणकारी समाधान प्रस्तुत करता हूं, और प्रश्न के कोड में सुधार करता हूं।

मैं इस तथ्य को छिपाना नहीं चाहता हूं कि मैंने स्पीकर के समाधान का अध्ययन किया है और मेरे समाधान में एकीकृत किया है।

// Assume that the texture to which uTextureSlotNumber refers contains 
// a rendering of the digits '' 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); 
    } 
} 

समारोह ValueToDigits एक चल बिन्दु संख्या की व्याख्या एक अंक के साथ एक सरणी को भरती है। सरणी में प्रत्येक नंबर (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); 
    } 
} 

कॉल ValueToDigits और अंकों खोजने के लिए और textur वर्तमान टुकड़ा के लिए समन्वय करता है।

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

यहां मेरा अद्यतन खंड शेडर है, जिसे मेरे मूल प्रश्न में लिस्टिंग में छोड़ दिया जा सकता है। यह दशमलव-डिजिटली-खोज एल्गोरिदम स्पीक्टेर का प्रस्ताव है, इस तरह से, जो विरासत जीएलएसएल 1.20 बोलीभाषा का उपयोग कर रहा हूं, उसके साथ भी संगत है। उस बाधा के बिना, Spektre का समाधान, ज़ाहिर है, और अधिक सुरुचिपूर्ण और शक्तिशाली है।

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 '' 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 
} 
संबंधित मुद्दे