C++ 着色器和纹理坐标的问题
我有一个着色器,我正在尝试使用,我遇到了一个我无法解决的问题,因为我对glsl的知识有限。 我正在使用纹理作为遮罩,为了调试这个问题,我只需使用这个纹理像素颜色作为gl_FragColor,我将发布一些图像来显示它的外观和应该的外观 图像链接; 它似乎与gl_TexCoord[0]中的坐标有关。xy未获得“溶解”纹理的正确坐标 main.cppC++ 着色器和纹理坐标的问题,c++,opengl,glsl,sfml,fragment-shader,C++,Opengl,Glsl,Sfml,Fragment Shader,我有一个着色器,我正在尝试使用,我遇到了一个我无法解决的问题,因为我对glsl的知识有限。 我正在使用纹理作为遮罩,为了调试这个问题,我只需使用这个纹理像素颜色作为gl_FragColor,我将发布一些图像来显示它的外观和应该的外观 图像链接; 它似乎与gl_TexCoord[0]中的坐标有关。xy未获得“溶解”纹理的正确坐标 main.cpp #include "Engine.h" #include <stdio.h> #include <iostream> #in
#include "Engine.h"
#include <stdio.h>
#include <iostream>
#include <windows.h>
int main(int argc, char *argv[])
{
try
{
Engine game;
game.Run();
}
catch (std::exception& err)
{
std::cout << "\nException: " << err.what() << std::endl;
}
return 0;
}
引擎
#pragma once
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <SFML/Audio.hpp>
#include <SFML/Network.hpp>
#include <vector>
#include <iostream>
class Engine
{
public:
Engine();
void Run();
void HandleEvents(sf::Time deltaTime);
void Update(sf::Time deltaTime);
void BuildVertices();
void Draw();
private:
bool running;
bool hasFocus;
bool fullScreen;
sf::RenderWindow mainWindow;
sf::Time deltaTime;
sf::Event event;
sf::Vector2i screenResolution;
sf::Vector2i mousePosition;
sf::VertexArray vertices;
sf::Vertex vertex;
sf::Shader dissolveShader;
sf::Texture dissolveTexture;
sf::RenderStates renderState;
float dissolveValue;
sf::Texture objectSpriteSheetTexture;
};
Engine.cpp
#include "Engine.h"
static const sf::Time TimePerFrame = sf::seconds(1.f / 60.f);
Engine::Engine()
: hasFocus(true)
, fullScreen(fullScreen)
, running(false)
, dissolveValue(1.0f)
, vertices(sf::Quads)
{
mainWindow.create(sf::VideoMode(640, 480), "Test", sf::Style::Titlebar);
mainWindow.setPosition(sf::Vector2i(0, 0));
screenResolution.x = 640;
screenResolution.y = 480;
// 512x512 sheet, each sprite is 128x128
if (!objectSpriteSheetTexture.loadFromFile("ObjectSheet.png"))
std::cout << "failed to load ObjectSheet.png" << std::endl;
if (!dissolveTexture.loadFromFile("DissolveTexture.png"))
std::cout << "failed to load DissolveTexture.png" << std::endl;
if (!dissolveShader.loadFromFile("DissolveShader.frag", sf::Shader::Fragment))
{
std::cout << "failed to load DissolveShader.frag" << std::endl;
}
dissolveShader.setUniform("sourceTexture", sf::Shader::CurrentTexture);
dissolveShader.setUniform("dissolveTexture", dissolveTexture);
renderState.shader = &dissolveShader;
renderState.texture = &objectSpriteSheetTexture;
}
void Engine::Run()
{
// main loop
sf::Clock clock;
sf::Time timeSinceLastUpdate = sf::Time::Zero;
sf::Time elapsedTime;
running = true;
while(running)
{
elapsedTime = clock.restart();
timeSinceLastUpdate += elapsedTime;
HandleEvents(TimePerFrame);
while(timeSinceLastUpdate > TimePerFrame)
{
timeSinceLastUpdate -= TimePerFrame;
Update(TimePerFrame);
}
BuildVertices();
Draw();
}
}
void Engine::HandleEvents(sf::Time deltaTime)
{
mousePosition = sf::Mouse::getPosition(mainWindow);
while(mainWindow.pollEvent(event))
{
if(event.type == sf::Event::Closed)
mainWindow.close();
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::Escape)
{
running = false;
}
}
}
}
void Engine::Update(sf::Time deltaTime)
{
}
void Engine::BuildVertices()
{
vertices.clear();
int frameSize = 128;
sf::Vector2i objectPosition(100, 100);
sf::Vector2i spriteSheetTextureCoordinates(0, 128);
vertex.position.x = objectPosition.x;
vertex.position.y = objectPosition.y;
vertex.texCoords.x = spriteSheetTextureCoordinates.x;
vertex.texCoords.y = spriteSheetTextureCoordinates.y;
vertices.append(vertex);
vertex.position.x = objectPosition.x + frameSize;
vertex.position.y = objectPosition.y;
vertex.texCoords.x = spriteSheetTextureCoordinates.x + frameSize;
vertex.texCoords.y = spriteSheetTextureCoordinates.y;
vertices.append(vertex);
vertex.position.x = objectPosition.x + frameSize;
vertex.position.y = objectPosition.y + frameSize;
vertex.texCoords.x = spriteSheetTextureCoordinates.x + frameSize;
vertex.texCoords.y = spriteSheetTextureCoordinates.y + frameSize;
vertices.append(vertex);
vertex.position.x = objectPosition.x;
vertex.position.y = objectPosition.y + frameSize;
vertex.texCoords.x = spriteSheetTextureCoordinates.x;
vertex.texCoords.y = spriteSheetTextureCoordinates.y + frameSize;
vertices.append(vertex);
}
void Engine::Draw()
{
mainWindow.clear(sf::Color::Black);
dissolveShader.setUniform("dissolveValue", dissolveValue);
mainWindow.draw(vertices, renderState);
mainWindow.display();
}
顶点着色器是由sfml处理的标准传递
片段着色器
#version 130
// used as the mask to determine if a pixel of the source texture should be drawn, 128x128
uniform sampler2D dissolveTexture;
// the texture of the object i'm drawing, a 128x128 part of a 512x512 sprite sheet
uniform sampler2D sourceTexture;
// set to 1.0 for debug
uniform float dissolveValue;
void main( void )
{
vec4 sourceColor = texture2D(sourceTexture, gl_TexCoord[0].xy);
vec4 maskColor = texture2D(dissolveTexture, gl_TexCoord[0].xy);
if(maskColor.r <= dissolveValue)
{
// it would return the source pixel color here one the issue is solved
// gl_FragColor = sourceColor;
// debuging, so returning the mask textures pixel color
gl_FragColor = maskColor;
}
else
{
gl_FragColor = sourceColor;
}
}
我可能忽略了一些简单的事情,所以如果有人能给我指出正确的方向,我将不胜感激,谢谢 GLSL函数的纹理坐标范围为0.0到1.0,其中0.0,0.0通常是纹理图像的左下角,1.0,1.0是纹理图像的右上角 但是,SFML库根据当前纹理sf::Shader::CurrentTexture的大小缩放纹理坐标。这意味着必须在当前纹理大小的范围内设置纹理坐标: 这意味着您必须像这样设置纹理坐标:
void Engine::BuildVertices()
{
vertices.clear();
int frameSize = 128;
sf::Vector2i objectPosition(100, 100);
sf::Vector2i texSize(512, 512);
vertex.position = sf::Vector2f(objectPosition.x, objectPosition.y);
vertex.texCoords = sf::Vector2f(0.0f, 0.0f);
vertices.append(vertex);
vertex.position = sf::Vector2f(objectPosition.x + frameSize, objectPosition.y);
vertex.texCoords = sf::Vector2f(texSize.x, 0.0f);
vertices.append(vertex);
vertex.position = sf::Vector2f(objectPosition.x + frameSize, objectPosition.y + frameSize);
vertex.texCoords = sf::Vector2f(texSize.x, texSize.y);
vertices.append(vertex);
vertex.position = sf::Vector2f(objectPosition.x, objectPosition.y + frameSize);
vertex.texCoords = sf::Vector2f(0.0f, texSize.y);
vertices.append(vertex);
}
您有一个大小为128*128的遮罩纹理,您有一个大小为512*512的平铺sprite 4*4平铺。我建议将纹理坐标偏移量uniform texOffset和纹理比例uniform texScale添加到片段着色器,允许选择纹理的平铺:
#version 130
uniform sampler2D dissolveTexture;
uniform sampler2D sourceTexture;
uniform float dissolveValue;
uniform vec2 texScale;
uniform vec2 texOffset;
void main( void )
{
vec4 sourceColor = texture2D(sourceTexture, texOffset+texScale*gl_TexCoord[0].xy);
vec4 maskColor = texture2D(dissolveTexture, gl_TexCoord[0].xy);
gl_FragColor = mix( sourceColor, maskColor, step(maskColor.r, dissolveValue) );
}
你必须在功能图中设置制服。比例由瓷砖行数和立柱数的倒数给出。偏移是平铺的索引乘以比例因子:
void Engine::Draw()
{
mainWindow.clear(sf::Color::Black);
dissolveValue = 0.5f;
dissolveShader.setUniform("dissolveValue", dissolveValue);
float scale_x = 1.0f/4.0f;
float scale_y = 1.0f/4.0f;
int i_x = 1; // column of tile (form 0 to 3)
int i_y = 2; // row of tile (form 0 to 3)
dissolveShader.setUniform("texScale", sf::Glsl::Vec2(scale_x, scale_y));
dissolveShader.setUniform("texOffset", sf::Glsl::Vec2(i_x*scale_x, i_y*scale_y));
mainWindow.draw(vertices, renderState);
mainWindow.display();
}
我们需要一个。好的,我能做到,很快就会完成,需要运行一个小时的例子,thanksTexture坐标应该在[0-1]范围内,虽然它可以超过这个范围,但这是其他的。您应该调试并检查指定的tex coordsI的值,我知道着色器的这一点,但是sfml不使用相同的坐标系。另外,我不知道如何像调试c++的着色器代码一样调试着色器代码您好,是的,我知道着色器中的坐标介于0.0和1.0之间,但是sfml中的顶点纹理坐标没有,如果我在构建sfml中的顶点时使用范围0.0到1.0,它将只显示拉伸到帧大小的1个像素。问题似乎是gl_TexCoord[0]以正确的0.0到1.0给出了sprite表中的纹理坐标,而我要求它们从0.0开始到1.0结束,我不确定如何真正解释它。精灵表是512x512,该帧从0,128开始,遮罩纹理是128x128从0,0开始。是的,如果我使用纹理坐标从0到512构建顶点,它将正确显示遮罩纹理。我想渲染精灵表的一部分,并使用着色器根据一个值遮罩其中的一部分,但是我无法从着色器中获得正确的遮罩纹理坐标,如果检查我上面链接的图像,我获得的坐标似乎与精灵表的比例(包括偏移)匹配,你可以看到它以4:1的像素比例渲染拉伸区域,并且有一个偏移,spritesheet纹理恰好是遮罩纹理大小的4倍,除非我尝试在着色器中获取遮罩纹理的纹理坐标,它们匹配512x512纹理,它们从匹配偏移的位置开始。不,遮罩没有平铺,相同的遮罩用于所有瓷砖Hanks Rabbid76,您的解决方案帮助我解决了它,我不得不更改一些内容,因为我发布的着色器是我创建的更大的着色器的一部分,对于该部分,gl_FragColor=mix sourceColor,maskColor,stepmaskColor.r,SolveValue;避免在着色器中使用if语句很好,如果我想跳过高于solveValue的片段,是否也可以使用相同的语句?避免使用