В LibGDX я создал шейдер для создания эффекта перехода, при котором круг образуется поверх изображения, где все, что находится за пределами круга, черное, а все, что находится внутри круга, отображается как обычно.Этот круг начинается с большого размера и уменьшается до нуля.Но у меня есть проблема, поскольку круг сокращается, он колеблется вокруг.Я также обнаружил, что у меня возникла эта проблема при использовании ShadeRenderer для создания круга, который также уменьшался со временем перед использованием шейдера.Я думаю, что проблема как-то связана с числами с плавающей запятой или способом отображения кругов.В любом случае, мне нужно знать, как мне это исправить, чтобы я мог плавно сжимать круг?
Вот рисунок, демонстрирующий мою проблему с колеблющимся кругом (который мне нужно сгладить): мой колеблющийся круг
Вот мой код шейдера фрагмента:
varying vec4 v_color;
varying vec3 v_position;
varying vec2 v_texCoord0;
uniform vec2 u_resolution;
uniform sampler2D u_sampler2D;
uniform float u_radius;
uniform int u_hasCircle;
void main() {
vec4 color = texture2D(u_sampler2D, v_texCoord0) * v_color;
vec2 relativePosition = gl_FragCoord.xy / u_resolution - .5;
relativePosition.x *= u_resolution.x / u_resolution.y;
float len = length(relativePosition);
if (u_hasCircle == 1 && len > u_radius) {
color = vec4(0, 0, 0, 1);
}
gl_FragColor = color;
}
А вот мой код вершинного шейдера, который запускается до этого:
атрибутvec4 a_color;атрибут vec3 a_position;атрибут vec2 a_texCoord0;
равномерный mat4 u_projTrans;Равномерное vec3 u_distort;
varying vec4 v_color;
varying vec3 v_position;
varying vec2 v_texCoord0;
void main() {
v_color = a_color;
v_position = a_position;
v_texCoord0 = a_texCoord0;
gl_Position = u_projTrans * vec4(a_position, 1.0);
}
Когда я хочу перейти к запуску, u_hasCircle передается 1, в противном случае - 0. Когда переход выполняется, я начинаю с передачи u_radius 1, а затем постепенно уменьшаюзначение до 0, используя FloatAction в LibGDX.Я посылаю эти значения в шейдер один раз за кадр.
Вот соответствующий Java-код Libgdx, который взаимодействует с шейдером:
public class PlayWorld extends Group implements InputProcessor, Disposable
{
//various members
private PlayScreen screen;
private OrthographicCamera camera;
private FloatAction transitionToBattleAction;
private final float TRANS_TO_BATTLE_DURATION = 10f;
private float circleSize;
private boolean hasCircle = false;
public PlayWorld(PlayWorld playWorld) {
this.playWorld = playWorld;
camera = new OrthographicCamera();
tiledMap = new TiledMapActor(camera);
addActor(tiledMap);
transitionToBattleAction = new FloatAction();
}
//function that triggers transition
public void enterBattle() {
transitionToBattleAction.reset();
transitionToBattleAction.setStart(0);
transitionToBattleAction.setEnd(1);
transitionToBattleAction.setDuration(TRANS_TO_BATTLE_DURATION);
addAction();
}
// this function gets called every frame
@Override
public void act(float delta) {
super.act(delta);
if (transitionToBattleAction.getValue() == 0) {
//this function is defined in code shown below
tiledMap.unsetCircleSize();
} else if (transitionToBattleAction.getValue() < 1) {
//this function is defined in code shown below
tiledMap.setCircleSize(
1 - transitionToBattleAction.getValue());
} else if (transitionToBattleAction.getValue() == 1) {
//this function is defined in code shown below
tiledMap.setCircleSize(
1 - transitionToBattleAction.getValue());
transitionToBattleAction.restart();
screen.getGame().setScreen("battle");
} else if (transitionToBattleAction.getValue() > 1) {
//this function is defined in code shown below
tiledMap.unsetCircleSize();
transitionToBattleAction.restart();
}
}
//this gets called whenever the window resizes
public void resize(int width, int height) {
// this function is defined in code shown below
tiledMap.resize(width, height);
}
//various other methods
}
public class TiledMapActor extends Actor implements InputProcessor, Disposable
{
//various variables
private ShaderProgram shader;
private OrthographicCamera camera;
private TiledMap map;
private OrthogonalTiledMapRenderer renderer;
private float UNIT_SCALE = 1 / 16f;
public TiledMapActor(OrthographicCamera camera) {
super();
this.camera = camera;
map = new TmxMapLoader().load("myMap.tmx");
renderer = new OrthogonalTiledMapRenderer(map, UNIT_SCALE);
shader = new ShaderProgram(
Gdx.files.internal("shaders/myshader.vsh"),
Gdx.files.internal("shaders/myshader.fsh");
System.out.println(
shader.isCompiled() ?
"shader compiled" : shader.getLog());
renderer.getBatch().setShader(shader);
shader.begin();
shader.setUniformi("u_hasCircle", 0);
shader.end();
}
// this is called every time the window changes size
// from the PlayScreen class, see code above
public void resize(int width, int height) {
camera.viewportWidth = width;
camera.viewportHeight = height;
camera.update();
shader.begin();
shader.setUniformf("u_resolution", (float)width, (float)height);
shader.end();
}
//this method is called from code above, seen PlayScreen class code
//
public void setCircleSize(float circleSize) {
this.circleSize = circleSize;
hasCircle = true;
shader.begin();
shader.setUniformf("u_radius", circleSize);
shader.setUniformi("u_hasCircle", 1);
shader.end();
}
//this method is called from code above, seen PlayScreen class code
//
public void unsetCircleSize() {
hasCircle = false;
shader.begin();
shader.setUniformi("u_hasCircle", 0);
shader.end();
}
// Various other methods
}