C++ 有符号距离字段的Alpha测试文本渲染创建扭曲的边
我试图在我的应用程序中使用符号距离场纹理表示的glyph atlas渲染文本,这意味着在每个像素中存储到最近轮廓的距离的纹理。 此距离场纹理是使用此算法从原始二进制glyph atlas纹理(0-轮廓线外,1-轮廓线内)生成的,该算法搜索纹理中每个像素周围的增量半径,直到找到状态相反的像素,然后存储找到该像素的距离。之后,所有距离都映射到0和1之间C++ 有符号距离字段的Alpha测试文本渲染创建扭曲的边,c++,opengl,textures,distance,text-rendering,C++,Opengl,Textures,Distance,Text Rendering,我试图在我的应用程序中使用符号距离场纹理表示的glyph atlas渲染文本,这意味着在每个像素中存储到最近轮廓的距离的纹理。 此距离场纹理是使用此算法从原始二进制glyph atlas纹理(0-轮廓线外,1-轮廓线内)生成的,该算法搜索纹理中每个像素周围的增量半径,直到找到状态相反的像素,然后存储找到该像素的距离。之后,所有距离都映射到0和1之间 //set size of signed distance field atlas atlas.width = binaryAtlasWidth*
//set size of signed distance field atlas
atlas.width = binaryAtlasWidth* pDistanceFieldResolution;
atlas.height = binaryAtlasHeight * pDistanceFieldResolution;
const unsigned int atlasPixelCount = (atlas.width * atlas.height);
atlas.buffer.resize(atlasPixelCount);
//temporary buffer for the distances of each pixel
std::vector<float> unmappedBuffer;
unmappedBuffer.resize(atlasPixelCount);
//support multisampling
unsigned int samplesPerOutPixel = ceil(1.0 / pDistanceFieldResolution);
//for mapping the values between 0 and 1 later
float maxDistance = 0.0;
float minDistance = 0.0;
for (unsigned int outPixel = 0; outPixel < atlasPixelCount; ++outPixel) {
//coordinate of the input sample
unsigned int outPixelX = outPixel%atlas.width;
unsigned int outPixelY = outPixel/atlas.width;
float distanceSum = 0.0f;
for (unsigned int sampleY = 0; sampleY < samplesPerOutPixel; ++sampleY) {
for (unsigned int sampleX = 0; sampleX < samplesPerOutPixel; ++sampleX) {
glm::uvec2 sampleCoord = glm::uvec2(outPixelX * samplesPerOutPixel+ sampleX, outPixelY * samplesPerOutPixel+ sampleY);
unsigned int samplePos = sampleCoord.x + sampleCoord.y*binaryAtlasWidth;
unsigned char sampleVal = buffer[samplePos];
//inital distance is maximum search radius(outside of glyph)
float dist = spread;
int found = 0;
unsigned int rad = 0;
while(!found && (rad*(!sampleVal)) < spread_pixels) {
//if sampleVal is 1(inside), search until found
float radius = (float)rad + 1.0f;
unsigned int compareCount = round(2.0f*radius*M_PI);
float step = 1.0 / (float)compareCount;
for (unsigned int t = 0; t < compareCount && !found; ++t) {
float theta = step*(float)t*360.0f;
glm::vec2 compareLocalCoord = glm::vec2(std::cos(theta), std::sin(theta))*radius;
glm::uvec2 compareCoord = sampleCoord + glm::uvec2(compareLocalCoord);
int comparePos = compareCoord.x + compareCoord.y*binaryAtlasWidth;
if (compareCoord.x >= 0 && compareCoord.x < binaryAtlasWidth&& compareCoord.y >= 0 && compareCoord.y < binaryAtlasHeight) {
unsigned char compareVal = buffer[comparePos];
if (compareVal != sampleVal ) {
float distance = sqrt(pow(compareLocalCoord.x, 2) + pow(compareLocalCoord.y, 2));
found = 1;
dist = std::min(distance * (1 - (sampleVal * 2)) , dist) ;
}
}
}
++rad;
}
distanceSum += dist;
}
}
float avgDistance = distanceSum / (float)(samplesPerOutPixel*samplesPerOutPixel);
printf("pixel %i of %i has %f distance\n", outPixel, atlasPixelCount, avgDistance);
unmappedBuffer[outPixel] = avgDistance;
maxDistance = std::max(maxDistance, avgDistance);
minDistance = std::min(minDistance, avgDistance);
}
minDistance *= -1.0;
float diff = maxDistance + minDistance;
//map all values between 0 and 255
for(unsigned int p = 0; p < atlasPixelCount; ++p) {
float toMap = unmappedBuffer[p];
float mappedDistance = 1.0f - (toMap + minDistance) / diff;
atlas.buffer[p] = mappedDistance * 255;
}
//设置有符号距离场图集的大小
atlas.width=二进制AtlasWidth*pDistanceFieldResolution;
atlas.height=二进制AtlashHeight*pDistanceFieldResolution;
常量unsigned int atlasPixelCount=(atlas.width*atlas.height);
atlas.buffer.resize(atlasPixelCount);
//每个像素距离的临时缓冲区
std::向量未映射缓冲区;
unmappedBuffer.resize(atlasPixelCount);
//支持多采样
无符号int-samplesPerOutPixel=ceil(1.0/pDistanceFieldResolution);
//用于以后在0和1之间映射值
浮动最大距离=0.0;
浮动距离=0.0;
for(无符号int-outPixel=0;outPixel=0&&compareCoord.x=0&&compareCoord.y
此算法创建以下结果:
266x183输入纹理
未进行下采样的SDF结果(仍为266 x 183)
带下采样的SDF结果(106 x 73)
启用alpha测试时渲染结果(alpha大于0.5时通过):
无下采样、最近滤波
下采样、最近滤波
无下采样,线性滤波
下采样线性滤波
我的意思是,我正在达到目标,但实际上我希望得到如中所示的精确边缘。对于精确的边,我缺少什么
PS:my fragment着色器当前仅使用距离纹理值作为alpha值。(
color=vec4(1,1,1,距离);
)它们使用更高的下采样率,距离变换看起来不够精确。有关快速准确的距离变换算法,请参阅。我只想感谢您在这里提供的宝贵资源!它们使用更高的下采样率,距离变换看起来不够精确。有关快速准确的距离变换算法,请参阅。我只想感谢您在这里提供的宝贵资源!