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()
फैंसी रेट्रो फ़ॉन्ट के लिए दूसरी बार ऊपर उठ जाएगा! – HolyBlackCat
यह प्रभावशाली काम है! धन्यवाद! किसी कारण से, हालांकि मेरी मशीनों में से एक में जीएलएसएल> 4.20 (वास्तव में 4.30) है, इसके कंपाइलर अक्षर अक्षर जैसे '' '' ('कहते हैं' 'त्रुटि: 0:22:' ': अवैध चरित्र (') (0x27) ')। तो मुझे इन्हें पूरे पूर्णांक अक्षरों के साथ प्रतिस्थापित करना पड़ा, लेकिन फिर मैं यह काम करने में सक्षम था। बहुत ही शांत! मुझे यह उल्लेख करना चाहिए था कि मैं वास्तव में 1.20 तक जीएलएसएल संस्करणों का समर्थन करने में सक्षम होना चाहता हूं लेकिन यह आपके समाधान से अलग नहीं होना चाहिए, विशेष रूप से मूल दशमलवकरण एल्गोरिदम ऐसा लगता है कि यह पोर्टेबल भी होना चाहिए। – jez
इसके अलावा: मैं बाइनरी में प्रतिपादन के बारे में अपना मुद्दा लेता हूं और इसके बजाय खुशी से ऐसा करता हूं, क्योंकि यह ऑन-ऑफ पिक्सेल के अनुक्रम के डीकोडिंग के बाद स्क्रीन कैप्चर को स्वचालित करने के लिए पर्याप्त आसान होना चाहिए। यह वास्तव में एक अधिक उपयोगी सामान्य उद्देश्य समाधान हो सकता है। लेकिन क्या मैं इसे जीएलएसएल संस्करणों में भी कर सकता हूं? मैं 'FloatBitsToUint' के बारे में जानता हूं लेकिन यह केवल 3.30+ संस्करण में उपलब्ध है। जब आपने "बाइनरी एक्सेस" के बारे में बात की थी, तो क्या आपके मन में अन्य कार्य हैं, और यदि ऐसा होगा तो वे विरासत प्रणाली पर उपलब्ध होंगे? यह एक अलग अलग सवाल है जो मुझे लगता है ... – jez