2015-07-30 18 views
5

Vì vậy, tôi có một hiệu ứng nước được áp dụng cho một hình ảnh hình chữ nhật là nước của tôi để áp dụng một hàm sóng sin trên nó. Nó chỉ được áp dụng cho TextureRegion này:LibGdx Có cách nào để áp dụng đổ bóng cho một phần của lô sprite cho hiệu ứng nước không?

Water.java

public void updateshaders(){ 

    float dt = Gdx.graphics.getDeltaTime(); 

    if(waterShader != null){ 

     time += dt ; 
     float angle = time * (2 * MathUtils.PI); 
     if (angle > (2 * MathUtils.PI)) 
      angle -= (2 * MathUtils.PI); 

     Gdx.gl20.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); 
     Gdx.gl20.glEnable(GL20.GL_BLEND); 
     waterShader.setUniformMatrix("u_projTrans", gs.cam.combined); 

     waterShader.begin(); 
     waterShader.setUniformf("timedelta", -angle); 
     waterShader.end(); 
    } 
} 
@Override 
public void draw(SpriteBatch g) { 
    g.end(); 
    updateshaders(); 
    g.setProjectionMatrix(gs.cam.combined); 
    g.setShader(waterShader); 
    g.begin(); 
    g.draw(gs.gsm.rm.water_top, x, y + height - gs.gsm.rm.water_top.getRegionHeight(), width, gs.gsm.rm.water_top.getRegionHeight()); 
    g.draw(gs.gsm.rm.water, x, y, width, height - gs.gsm.rm.water_top.getRegionHeight()); 
    g.end(); 
    g.setShader(null); 
    g.begin(); 
} 

Imgur

Tôi muốn thêm hiệu ứng này để tất cả mọi thứ trong hình chữ nhật màu đỏ. Tôi đã nghĩ đến việc xóa bỏ hình ảnh SpriteBatch và cắt ra một hình ảnh của vùng, áp dụng biến dạng rồi vẽ lại nó trên bản gốc, sau đó hoàn tất phần còn lại của chuỗi hiển thị của tôi.

CẬP NHẬT: Vì vậy, giải pháp của tôi đã hoạt động ... sorta. Nó rất chậm. Có vẻ đúng nhưng làm cho trò chơi không thể phát và chậm. (Có thể là một chút khó có thể nhận thấy trong gif nhưng có vẻ tốt trong trò chơi.) gif

Code mới:

Water.java

public void draw(SpriteBatch g) { 
    g.end(); 
    updateshaders(); 
    //Distortion 
    coords = gs.cam.project(new Vector3(x,y,0)); 
    if(scr != null){scr.getTexture().dispose();} 
    scr = ScreenUtils.getFrameBufferTexture(
      (int)coords.x,(int)coords.y, 
      (int)(width * scaleX),(int)((height - gs.gsm.rm.water_top.getRegionHeight()/4) * scaleY)); 

    if(scr != null){ 
     g.setShader(waterShader2); 
     g.begin(); 
     g.draw(scr, 
      x,y, 
      width,height- gs.gsm.rm.water_top.getRegionHeight()/4); 
     g.end(); 
    } 
    //SURFACE WAVES 
    g.setShader(waterShader); 
    g.begin(); 
    g.draw(gs.gsm.rm.water_top, x, y + height - gs.gsm.rm.water_top.getRegionHeight(), width, gs.gsm.rm.water_top.getRegionHeight()); 
    g.end(); 
    //BACK TO NORMAL 
    g.setShader(null); 
    g.begin(); 
    g.draw(gs.gsm.rm.water, x, y, width, height - gs.gsm.rm.water_top.getRegionHeight()); 
} 

UPDATE: tôi đã cố gắng Tenfour04 của giải pháp và nó đã làm việc ... sorta. Trong khi có một hiệu ứng méo mó, và trò chơi chạy ở chế độ FPS đầy đủ, sự biến dạng làm cho nền được hiển thị. Điều này là do đổ bóng đang được áp dụng cho các kết cấu, không chỉ trong phạm vi của khu vực mà tôi lấy sử dụng:

scr = new TextureRegion(((PlayGameState) gs).frameBuffer.getColorBufferTexture(), 
      (int)coords.x, (int)coords.y, 
      (int)(width * scaleX),(int)((height - gs.gsm.rm.water_top.getRegionHeight()/4) * scaleY)); 

werid

Trả lời

3

Trên mỗi khung hình, bạn đang vứt bỏ và tái tạo một pixmap và một Texture, và sau đó chụp màn hình để kết cấu đó. Đây là một hoạt động cực kỳ chậm được lặp đi lặp lại nhiều lần.

Thay vào đó, bạn có thể kết xuất trò chơi của mình trực tiếp vào bộ đệm khung hình liên tục.

private FrameBuffer frameBuffer; 
private final Matrix4 idt = new Matrix4(); 

public void render() { 
    if (frameBuffer == null){ 
     //Normally this would go in the resize method, but that causes issues on iOS 
     //because resize isn't always called on the GL thread in iOS. So lazy load here. 
     try { 
      frameBuffer = new FrameBuffer(Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false); 
     } catch (GdxRuntimeException e){ 
      frameBuffer = new FrameBuffer(Format.RGB565, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false); 
      //RGBA8888 not supported on all devices. You might instead want to turn off 
      //the water effect if it's not supported, because 565 is kinda ugly. 
     } 
    } 

    frameBuffer.begin(); 
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); 
    //draw everything that is behind the water layer here 
    frameBuffer.end(); 

    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); 
    //Draw the frame buffer texture to the screen: 
    spriteBatch.setProjectionMatrix(idt); 
    spriteBatch.begin(); 
    spriteBatch.draw(frameBuffer.getColorBufferTexture(), -1, 1, 2, -2); //IIRC, you need to vertically flip it. If I remembered wrong, then do -1, -1, 2, 2 
    spriteBatch.end(); 

    water.draw(spriteBatch, frameBuffer.getColorBufferTexture()); 

    //draw stuff that is in front of the water here 
} 

Và sau đó sửa đổi lớp nước của bạn như sau. Nếu tôi nhớ chính xác, kết cấu màn hình bị lộn ngược, vì vậy bạn có thể phải lật một số môn toán của mình. Tôi đã không kiểm tra toán học của bạn dưới đây để biết nếu bạn đã tài khoản cho điều đó.

public void draw(SpriteBatch g, Texture scr) { 
    updateshaders(); 
    //Distortion 
    coords = gs.cam.project(new Vector3(x,y,0)); 

    if(scr != null){ 
     g.setShader(waterShader2); 
     g.begin(); 
     g.draw(scr, 
      x,y, 
      width,height- gs.gsm.rm.water_top.getRegionHeight()/4); 
     g.end(); 
    } 
    //SURFACE WAVES 
    g.setShader(waterShader); 
    g.begin(); 
    g.draw(gs.gsm.rm.water_top, x, y + height - gs.gsm.rm.water_top.getRegionHeight(), width, gs.gsm.rm.water_top.getRegionHeight()); 
    g.end(); 
    //BACK TO NORMAL 
    g.setShader(null); 
    g.begin(); 
    g.draw(gs.gsm.rm.water, x, y, width, height - gs.gsm.rm.water_top.getRegionHeight()); 
} 

Một điều không được tối ưu hóa trong quy trình này là bạn sẽ vẽ tất cả các pixel phía sau lớp nước ít nhất hai lần. Một lần để vẽ nó trên bộ đệm khung, và sau đó một lần thứ hai khi bộ đệm khung được rút ra màn hình. Điều này có thể được tối ưu hóa sau này (nếu bạn đang lấp đầy tỷ lệ lấp đầy) bằng cách vẽ các công cụ sau nước chỉ trong các khu vực của chế độ xem được bao phủ bởi nước và sau đó thay thế bước vẽ kết cấu bộ đệm khung đến màn hình bằng cách vẽ nền công cụ bình thường. Điều này sẽ chỉ tốt nếu bạn xây dựng thành công bộ đệm khung RGBA8888, bộ đệm không được hỗ trợ trên tất cả Android.

+0

Điều duy nhất là tôi phải thay đổi ma trận chiếu trở lại máy ảnh trước khi lấy nước, tôi cũng phải lấy một vùng của kết cấu đệm khung để đạt được mục tiêu của mình –

+0

Giải pháp của bạn rất tuyệt vời cho phần hiệu suất , nhưng làm cách nào để đảm bảo trình đổ bóng được áp dụng cho chỉ 'TextureRegion' trong hộp màu đỏ? –

+0

Toàn bộ kết cấu được vẽ ra màn hình và sau đó lớp nước của bạn vẽ lại các vùng cần hiệu ứng. Tôi cho rằng bạn đã có một phần làm việc với màn hình có kích thước mà bạn nhận được từ ScreenUtils. Bạn không chắc chắn cách thức lớp nước của bạn hoạt động vì tất cả các biến. – Tenfour04

Các vấn đề liên quan