libgdx 3D 渲染优化

原文地址:http://blog.xoppa.com/3d-frustum-culling-with-libgdx/

非翻译,详细内容请见原文,捡点我能理解的说说吧~

关于矩阵之类的知识可以看一下 http://www.cppblog.com/lovedday/archive/2008/01/09/40813.html 我也不懂~~

 

渲染3D场景的时候,可见物件的数量要远远小于物件总数。

试想,在铺了一地地砖的时候,视角对着天,这时候需要渲染的地砖就没有了。摄像机照不到的地方,完全没有必要渲染。

只渲染可视视角范围内的物件,对于性能的提升是很大的。

直接上测试代码:

  1 package com.mygdx.game;

  2 

  3 import com.badlogic.gdx.ApplicationListener;

  4 import com.badlogic.gdx.Gdx;

  5 import com.badlogic.gdx.assets.AssetManager;

  6 import com.badlogic.gdx.graphics.Camera;

  7 import com.badlogic.gdx.graphics.Color;

  8 import com.badlogic.gdx.graphics.GL20;

  9 import com.badlogic.gdx.graphics.PerspectiveCamera;

 10 import com.badlogic.gdx.graphics.g2d.BitmapFont;

 11 import com.badlogic.gdx.graphics.g3d.Environment;

 12 import com.badlogic.gdx.graphics.g3d.Model;

 13 import com.badlogic.gdx.graphics.g3d.ModelBatch;

 14 import com.badlogic.gdx.graphics.g3d.ModelInstance;

 15 import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;

 16 import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;

 17 import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;

 18 import com.badlogic.gdx.math.Vector3;

 19 import com.badlogic.gdx.math.collision.BoundingBox;

 20 import com.badlogic.gdx.scenes.scene2d.Stage;

 21 import com.badlogic.gdx.scenes.scene2d.ui.Label;

 22 import com.badlogic.gdx.utils.Array;

 23 

 24 /**

 25  * Created by HanHongmin on 14-7-24.

 26  */

 27 public class FrustumCullingTestA implements ApplicationListener {

 28     protected PerspectiveCamera cam;

 29     protected CameraInputController camController;

 30     protected ModelBatch modelBatch;

 31     protected AssetManager assets;

 32     protected Array<ModelInstance> instances = new Array();

 33     protected Environment environment;

 34     protected boolean loading;

 35 

 36     protected Stage stage;

 37     protected Label label;

 38     protected BitmapFont font;

 39     protected StringBuilder stringBuilder;

 40     private Vector3 tempPosition = new Vector3();

 41 

 42     @Override

 43     public void create () {

 44         stage = new Stage();

 45         font = new BitmapFont();

 46         label = new Label(" ", new Label.LabelStyle(font, Color.WHITE));

 47         stage.addActor(label);

 48         stringBuilder = new StringBuilder();

 49 

 50         modelBatch = new ModelBatch();

 51         environment = new Environment();

 52         environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));

 53         environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));

 54 

 55         cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

 56         cam.position.set(0f, 7f, 10f);

 57         cam.lookAt(0,0,0);

 58         cam.near = 1f;

 59         cam.far = 300f;

 60         cam.update();

 61 

 62         camController = new CameraInputController(cam);

 63         Gdx.input.setInputProcessor(camController);

 64 

 65         assets = new AssetManager();

 66         assets.load("data/box.g3db", Model.class);

 67         assets.load("data/box2.g3db", Model.class);

 68         loading = true;

 69     }

 70 

 71     private void doneLoading() {

 72         Model t1 = assets.get("data/box.g3db", Model.class);

 73         Model t2 = assets.get("data/box2.g3db", Model.class);

 74 

 75         for(int i=0;i<100;i++){

 76             for(int j=0;j<100;j++){

 77                 Model t;

 78                 if((i+j)%2==0){

 79                     t = t1;

 80                 }else{

 81                     t=t2;

 82                 }

 83                 ModelInstance shipInstance = new ModelInstance(t);

 84                 shipInstance.transform.setToTranslation(i, j, 0);//设置位置

 85                 instances.add(shipInstance);

 86             }

 87         }

 88 

 89         loading = false;

 90     }

 91 

 92     private int visibleCount;

 93     @Override

 94     public void render () {

 95         if (loading && assets.update())

 96             doneLoading();

 97         camController.update();

 98 

 99         Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

100         Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

101 

102         modelBatch.begin(cam);

103         visibleCount = 0;

104         for (final ModelInstance instance : instances) {

105             if (isVisible(cam, instance)) {

106                 modelBatch.render(instance, environment);

107                 visibleCount++;

108             }

109         }

110         modelBatch.end();

111 

112         stringBuilder.setLength(0);

113         stringBuilder.append(" FPS: ").append(Gdx.graphics.getFramesPerSecond());

114         stringBuilder.append(" Visible: ").append(visibleCount);

115         label.setText(stringBuilder);

116         stage.draw();

117     }

118 

119     protected boolean isVisible(final Camera cam, final ModelInstance instance) {

120         instance.transform.getTranslation(tempPosition);//把位置信息放到tempPosition中

121         return cam.frustum.pointInFrustum(tempPosition);//frustum平截头体,表示的就是可视范围

122     }

123 

124     @Override

125     public void dispose () {

126         modelBatch.dispose();

127         instances.clear();

128         assets.dispose();

129     }

130 

131     @Override

132     public void resize(int width, int height) {

133         stage.getViewport().update(width, height, true);

134     }

135 

136     @Override

137     public void pause() {

138     }

139 

140     @Override

141     public void resume() {

142     }

143 }
View Code

以上代码中,关键部分是isVisible函数,该函数中计算了物件位置是否是在可视范围内。

这种算法稍稍有点瑕疵,运行即可看出效果。如果一个物件的位置不在可视范围内,但是此物件有一角却在,常理来说是应该显示的,而实际却没有显示出来。

上代码吧:

  1 package com.mygdx.game;

  2 

  3 import com.badlogic.gdx.ApplicationListener;

  4 import com.badlogic.gdx.Gdx;

  5 import com.badlogic.gdx.assets.AssetManager;

  6 import com.badlogic.gdx.graphics.Camera;

  7 import com.badlogic.gdx.graphics.Color;

  8 import com.badlogic.gdx.graphics.GL20;

  9 import com.badlogic.gdx.graphics.PerspectiveCamera;

 10 import com.badlogic.gdx.graphics.g2d.BitmapFont;

 11 import com.badlogic.gdx.graphics.g3d.Environment;

 12 import com.badlogic.gdx.graphics.g3d.Model;

 13 import com.badlogic.gdx.graphics.g3d.ModelBatch;

 14 import com.badlogic.gdx.graphics.g3d.ModelInstance;

 15 import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;

 16 import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;

 17 import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;

 18 import com.badlogic.gdx.math.Vector3;

 19 import com.badlogic.gdx.math.collision.BoundingBox;

 20 import com.badlogic.gdx.scenes.scene2d.Stage;

 21 import com.badlogic.gdx.scenes.scene2d.ui.Label;

 22 import com.badlogic.gdx.utils.Array;

 23 

 24 /**

 25  * Created by HanHongmin on 14-7-24.

 26  */

 27 public class FrustumCullingTest implements ApplicationListener {

 28     protected PerspectiveCamera cam;

 29     protected CameraInputController camController;

 30     protected ModelBatch modelBatch;

 31     protected AssetManager assets;

 32     protected Array<GameObject> instances = new Array();

 33     protected Environment environment;

 34     protected boolean loading;

 35 

 36     protected Stage stage;

 37     protected Label label;

 38     protected BitmapFont font;

 39     protected StringBuilder stringBuilder;

 40     private Vector3 tempPosition = new Vector3();

 41 

 42     @Override

 43     public void create () {

 44         stage = new Stage();

 45         font = new BitmapFont();

 46         label = new Label(" ", new Label.LabelStyle(font, Color.WHITE));

 47         stage.addActor(label);

 48         stringBuilder = new StringBuilder();

 49 

 50         modelBatch = new ModelBatch();

 51         environment = new Environment();

 52         environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));

 53         environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));

 54 

 55         cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

 56         cam.position.set(0f, 7f, 10f);

 57         cam.lookAt(0,0,0);

 58         cam.near = 1f;

 59         cam.far = 30f;//视角最远

 60         cam.update();

 61 

 62         camController = new CameraInputController(cam);

 63         Gdx.input.setInputProcessor(camController);

 64 

 65         assets = new AssetManager();

 66         assets.load("data/box.g3db", Model.class);

 67         assets.load("data/box2.g3db", Model.class);

 68         loading = true;

 69     }

 70 

 71     private void doneLoading() {

 72         Model t1 = assets.get("data/box.g3db", Model.class);

 73         Model t2 = assets.get("data/box2.g3db", Model.class);

 74 

 75         for(int i=0;i<100;i++){

 76             for(int j=0;j<100;j++){

 77                 Model t;

 78                 if((i+j)%2==0){

 79                     t = t1;

 80                 }else{

 81                     t=t2;

 82                 }

 83                 GameObject shipInstance = new GameObject(t);

 84                 shipInstance.transform.setToTranslation(i, j, 0);//设置位置

 85                 instances.add(shipInstance);

 86             }

 87         }

 88 

 89         loading = false;

 90     }

 91 

 92     private int visibleCount;

 93     @Override

 94     public void render () {

 95         if (loading && assets.update())

 96             doneLoading();

 97         camController.update();

 98 

 99         Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

100         Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

101 

102         modelBatch.begin(cam);

103         visibleCount = 0;

104         for (final GameObject instance : instances) {

105             if (isVisible(cam, instance)) {

106                 modelBatch.render(instance, environment);

107                 visibleCount++;

108             }

109         }

110         modelBatch.end();

111 

112         stringBuilder.setLength(0);

113         stringBuilder.append(" FPS: ").append(Gdx.graphics.getFramesPerSecond());

114         stringBuilder.append(" Visible: ").append(visibleCount);

115         label.setText(stringBuilder);

116         stage.draw();

117     }

118 

119     protected boolean isVisible(final Camera cam, final GameObject instance) {

120         instance.transform.getTranslation(tempPosition);

121         tempPosition.add(instance.center);

122         return cam.frustum.boundsInFrustum(tempPosition, instance.dimensions);

123     }

124 

125     @Override

126     public void dispose () {

127         modelBatch.dispose();

128         instances.clear();

129         assets.dispose();

130     }

131 

132     @Override

133     public void resize(int width, int height) {

134         stage.getViewport().update(width, height, true);

135     }

136 

137     @Override

138     public void pause() {

139     }

140 

141     @Override

142     public void resume() {

143     }

144 

145 

146 

147     public static class GameObject extends ModelInstance {

148         public final Vector3 center = new Vector3();

149         public final Vector3 dimensions = new Vector3();

150 

151         private final static BoundingBox bounds = new BoundingBox();

152 

153         public GameObject(Model model) {

154             super(model);

155             calculateBoundingBox(bounds);

156             center.set(bounds.getCenter());

157             dimensions.set(bounds.getDimensions());

158         }

159     }

160 }

这个怎么算的,其实我想说:呵呵!我也不懂!!!谁整明白了请告诉我啊~

估计是看见一点就显示吧。反正是打到我们想要的效果了。

原文作者提到,当物件旋转时,可能会出现问题。贴一下原作最后的代码:

  1 package com.mygdx.game;

  2 

  3 import com.badlogic.gdx.ApplicationListener;

  4 import com.badlogic.gdx.Gdx;

  5 import com.badlogic.gdx.assets.AssetManager;

  6 import com.badlogic.gdx.graphics.Camera;

  7 import com.badlogic.gdx.graphics.Color;

  8 import com.badlogic.gdx.graphics.GL20;

  9 import com.badlogic.gdx.graphics.PerspectiveCamera;

 10 import com.badlogic.gdx.graphics.g2d.BitmapFont;

 11 import com.badlogic.gdx.graphics.g3d.Environment;

 12 import com.badlogic.gdx.graphics.g3d.Model;

 13 import com.badlogic.gdx.graphics.g3d.ModelBatch;

 14 import com.badlogic.gdx.graphics.g3d.ModelInstance;

 15 import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;

 16 import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;

 17 import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;

 18 import com.badlogic.gdx.math.Vector3;

 19 import com.badlogic.gdx.math.collision.BoundingBox;

 20 import com.badlogic.gdx.scenes.scene2d.Stage;

 21 import com.badlogic.gdx.scenes.scene2d.ui.Label;

 22 import com.badlogic.gdx.utils.Array;

 23 

 24 /**

 25  * Created by HanHongmin on 14-7-24.

 26  */

 27 public class FrustumCullingTestC implements ApplicationListener {

 28     protected PerspectiveCamera cam;

 29     protected CameraInputController camController;

 30     protected ModelBatch modelBatch;

 31     protected AssetManager assets;

 32     protected Array<GameObject> instances = new Array();

 33     protected Environment environment;

 34     protected boolean loading;

 35 

 36     protected Stage stage;

 37     protected Label label;

 38     protected BitmapFont font;

 39     protected StringBuilder stringBuilder;

 40     private Vector3 tempPosition = new Vector3();

 41 

 42     @Override

 43     public void create () {

 44         stage = new Stage();

 45         font = new BitmapFont();

 46         label = new Label(" ", new Label.LabelStyle(font, Color.WHITE));

 47         stage.addActor(label);

 48         stringBuilder = new StringBuilder();

 49 

 50         modelBatch = new ModelBatch();

 51         environment = new Environment();

 52         environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));

 53         environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));

 54 

 55         cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

 56         cam.position.set(0f, 7f, 10f);

 57         cam.lookAt(0,0,0);

 58         cam.near = 1f;

 59         cam.far = 30f;//视角最远

 60         cam.update();

 61 

 62         camController = new CameraInputController(cam);

 63         Gdx.input.setInputProcessor(camController);

 64 

 65         assets = new AssetManager();

 66         assets.load("data/box.g3db", Model.class);

 67         assets.load("data/box2.g3db", Model.class);

 68         loading = true;

 69     }

 70 

 71     private void doneLoading() {

 72         Model t1 = assets.get("data/box.g3db", Model.class);

 73         Model t2 = assets.get("data/box2.g3db", Model.class);

 74 

 75         for(int i=0;i<100;i++){

 76             for(int j=0;j<100;j++){

 77                 Model t;

 78                 if((i+j)%2==0){

 79                     t = t1;

 80                 }else{

 81                     t=t2;

 82                 }

 83                 GameObject shipInstance = new GameObject(t);

 84                 shipInstance.transform.setToTranslation(i, j, 0);//设置位置

 85                 instances.add(shipInstance);

 86             }

 87         }

 88 

 89         loading = false;

 90     }

 91 

 92     private int visibleCount;

 93     @Override

 94     public void render () {

 95         if (loading && assets.update())

 96             doneLoading();

 97         camController.update();

 98 

 99         Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

100         Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

101 

102         modelBatch.begin(cam);

103         visibleCount = 0;

104         for (final GameObject instance : instances) {

105             if (isVisible(cam, instance)) {

106                 modelBatch.render(instance, environment);

107                 visibleCount++;

108             }

109         }

110         modelBatch.end();

111 

112         stringBuilder.setLength(0);

113         stringBuilder.append(" FPS: ").append(Gdx.graphics.getFramesPerSecond());

114         stringBuilder.append(" Visible: ").append(visibleCount);

115         label.setText(stringBuilder);

116         stage.draw();

117     }

118 

119     protected boolean isVisible(final Camera cam, final GameObject instance) {

120         instance.transform.getTranslation(tempPosition);

121         tempPosition.add(instance.center);

122         return cam.frustum.sphereInFrustum(tempPosition, instance.radius);

123     }

124 

125     @Override

126     public void dispose () {

127         modelBatch.dispose();

128         instances.clear();

129         assets.dispose();

130     }

131 

132     @Override

133     public void resize(int width, int height) {

134         stage.getViewport().update(width, height, true);

135     }

136 

137     @Override

138     public void pause() {

139     }

140 

141     @Override

142     public void resume() {

143     }

144 

145 

146 

147     public static class GameObject extends ModelInstance {

148         public final Vector3 center = new Vector3();

149         public final Vector3 dimensions = new Vector3();

150         public final float radius;

151 

152         private final static BoundingBox bounds = new BoundingBox();

153 

154         public GameObject(Model model) {

155             super(model);

156             calculateBoundingBox(bounds);

157             center.set(bounds.getCenter());

158             dimensions.set(bounds.getDimensions());

159             radius = dimensions.len() / 2f;

160         }

161     }

162 }

 

注:以上代码我都有改过,比如GameObject的构造方法。会不会有问题我真不清楚。

另外还有两点:

1. Camera的far属性能够影响可视范围,不要忘了。

2. far边缘像是被刀切了一样,一条线,far越近越明显,是否有办法根据物件和摄像机位置再次筛选是否渲染呢?

far是一条直线,摄像机正对的中点看得更远一下可能更真实。

你可能感兴趣的:(libgdx)