我正试图在我的2D游戏中对爆炸实施冲击波效果 这些是我正在尝试的步骤 1)将所有东西绘制到帧缓冲区(纹理区域和网格) 2)从帧缓冲区获取纹理并垂直翻转 3)使用此http://empire-defense.crystalin.fr/blog/2d_shock_wave_texture_with_shader
中的着色器绘制生成的纹理这是我的渲染方法
resultBuf.begin();
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.gl20.glViewport(0, 0, resultBuf.getWidth(), resultBuf.getHeight());
Gdx.gl20.glEnable(GL20.GL_TEXTURE_2D);
batch.begin();
renderbackground();
batch.setProjectionMatrix(camera.combined);
if(imageObjDraw){
for(Integer type:imageObjects.keySet()){
if(type!=ImageObject.mountains&&type!=ImageObject.steelbridge1&&type!=ImageObject.steelbridge2&&type!=ImageObject.steelbridge3)for(ImageObject o:imageObjects.get(type))if(o.isInSquare(camRec))o.draw(batch);
}
}
batch.end();
if (meshDraw) {
//DRAWING MESHES
shaderPassThrough.begin();
Gdx.graphics.getGL20().glEnable(GL20.GL_BLEND);
shaderPassThrough.setUniformMatrix("u_projTrans", camera.combined);
shaderPassThrough.setUniformi("u_texture", 0);
for(Integer key:meshes.keySet()){
if(key!=MeshInfo.bridge){
LinkedList<myMesh> mlist=meshes.get(key);
Texture tex=meshTextures.get(key);
if(tex!=null)tex.bind(0);
for(myMesh m:mlist){
m.render();
}
}
}
shaderPassThrough.end();
}
batch.begin();
if(drawObjEnable){
drawObjects(batch);
vehicle.drawState0(batch);
drawParticles(batch);
}
if(particleDraw)PushTheLimits.animMan.render(batch);
if(bulletEnable)BulletManager.render(batch);
if(imageObjDraw){
for(Integer type:imageObjects.keySet()){
if(type==ImageObject.steelbridge1||type==ImageObject.steelbridge2||type==ImageObject.steelbridge3)for(ImageObject o:imageObjects.get(type))if(o.isInSquare(camRec))o.draw(batch);
}
}
batch.end();
if (meshDraw) {
//DRAWING MESHES
shaderPassThrough.begin();
Gdx.graphics.getGL20().glEnable(GL20.GL_BLEND);
shaderPassThrough.setUniformMatrix("u_projTrans", camera.combined);
shaderPassThrough.setUniformi("u_texture", 0);
for(Integer key:meshes.keySet()){
if(key==MeshInfo.bridge){
LinkedList<myMesh> mlist=meshes.get(key);
Texture tex=meshTextures.get(key);
if(tex!=null)tex.bind(0);
for(myMesh m:mlist){
m.render();
}
}
}
shaderPassThrough.end();
}
resultBuf.end();
batch.begin();
batch.setShader(shaderWave);
shaderWave.begin();
shaderWave.setUniformMatrix("u_projTrans", camera.combined);
shaderWave.setUniformi("sceneTex", 0);
shaderWave.setUniformf("center", new Vector2((explCoorX-camera.position.x+camera.effectivewidth/2f)/camera.zoom/screenW,(explCoorY-camera.position.y+camera.effectiveheight/2f)/camera.zoom/screenH));
shaderWave.setUniformf("time", waveElaps);
shaderWave.setUniformf("shockParams", new Vector3(10.0f, 0.8f, 0.1f));
resultTexReg.setRegion(resultBuf.getColorBufferTexture());
resultTexReg.flip(false, true);
resultTexReg.getTexture().bind();
batch.draw(resultTexReg, camera.position.x-camera.effectivewidth/2f,camera.position.y-camera.effectiveheight/2f,camera.effectivewidth,camera.effectiveheight);
batch.end();
batch.setShader(null);
这里是着色器 片段着色器
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D sceneTex; // 0
uniform vec2 center; // Mouse position
uniform float time; // effect elapsed time
uniform vec3 shockParams; // 10.0, 0.8, 0.1
varying vec2 v_texCoords;
varying vec2 proj;
void main()
{
float distance = distance(v_texCoords, center);
if ( (distance <= (time + shockParams.z)) && (distance >= (time - shockParams.z)) ) {
float diff = (distance - time);
float powDiff = 1.0 - pow(abs(diff*shockParams.x), shockParams.y);
float diffTime = diff * powDiff;
vec2 diffUV = normalize(v_texCoords-center);
v_texCoords = v_texCoords + (diffUV * diffTime);
}
gl_FragColor = texture2D(sceneTex, v_texCoords);
}
顶点着色器
attribute vec4 a_position;
attribute vec2 a_texCoord0;
uniform mat4 u_projTrans;
varying vec2 v_texCoords;
varying vec2 proj;
void main() {
//proj=u_projTrans.xy;
v_texCoords = a_texCoord0;
gl_Position = u_projTrans * a_position;
}
定义问题 总是应用于屏幕坐标的冲击波效应我的意思是中心变量I传递给片段着色器 - 即0,0-必须是我的box2d世界坐标的原点,但效果始终应用于屏幕的左下角,即使我移动了相机到地图效果的结尾是在屏幕的左下角,但我希望它在世界的起源0 0处的屏幕上非常左下方 我怀疑这个问题与我在相机位置绘制生成的纹理有关,而且我在着色器中使用相机作为投影矩阵,但我不太了解这个着色器主题和图形坐标实际上我对它进行了很好的研究,这对我来说似乎是正确的,但我无法看到这个错误并且需要帮助 在此先感谢请注释,如果我没有说清楚问题,我会编辑并添加所需的信息,甚至可能你想看一些屏幕截图?
答案 0 :(得分:0)
制服称为“中心”#39;在您的片段着色器中未在世界坐标中指定。当您将渲染到纹理的blit设置为屏幕时,它会在纹理坐标中指定。
因此,无论您的世界相机在哪里,坐标0,0始终位于屏幕的左下方,而1,1位于右上角。
为了为vec2&#39;中心传递适当的值,您必须将爆炸的坐标(或任何导致冲击波的坐标)从世界空间坐标系转换为纹理空间。
这样做的一种方法是将您的相机WVP矩阵(camera.combined)乘以世界坐标。如果它是透视摄像机,您可能需要将结果的xy除以w。这应该为您提供从-1,-1到1,1的剪辑空间坐标。然后,您需要通过添加1和减半将这些坐标重新映射到纹理坐标。您可以在顶点着色器中执行此操作并通过变量传递结果,或者您可以在CPU上执行此操作并将结果作为统一传递。