JSR-184 - Как выполнить рендеринг мира(world) в текстуру


Давайте поговорим о том как использовать 3D текстуры в мидлетах, использующих JSR-184. Использование текстур позволяет значительно повысить качество получаемого изображения. Кроме того умелое использование текстур позволяет повысить производительность вашего приложения. Например достаточно распространенный прием - рендеринг 3D мира в Image2D объект и дальнейшее использование его в качестве текстуры. При этом при последующих перерисовках экрана не нужно опять рендерить весь мир, ограничившись лишь активными(изменяющимися) объектами. При необходимости такую текстуру-задний план можно анимировать, изменяя 3D сцену.


В рассматриваемом примере при создании сцены будем использовать два мира (world).

Первый мир используется для рендеринга пирамиды в Image2D. Второй мир использует полученный Image2D объект в качестве текстуры Mesh сетки. Пирамиду будем задавать координатами ее вершин.

Рендеринг пирамиды в Image2D

texg3d.bindTarget(sceneTexture);// связываемся с Image2D объектом
texg3d.render(texWorld);// Выполняем рендеринг пирамиды в Image2D
...
g3d.bindTarget(g);// Указываем, что Image2D будем использовать в качестве цели Graphics3D
g3d.render(world);// Выполняем рендеринг мира

Размер грани создаваемой текстуры должен соответствовать положительной степени двойки (2, 4, 8, 16, 32, 64, 128, 256).

sceneTexture=new Image2D(Image2D.RGB,64,64);

Использование Image2D текстуры и рендеринг сетки

Создаем на основании Image2D объекта текстуру и используем ее в качестве текстуры плоскости.

Поскольку sceneTexture всего лишь ссылается на texture1 объект, вид sceneTexture можно менять в реальном времени. Делая это, мы получим анимированную текстуру.

Полный текст программы

Скачать архив с исходником (46 kB)

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.m3g.Camera;
import javax.microedition.lcdui.game.*;
 
import java.util.*;
 
publicclass map3DTextureextends MIDlet{
 
private Display d;
private mapTextureCanvas mapTextureCanvas;
 
public map3DTexture(){
mapTextureCanvas=new mapTextureCanvas(this);
d= Display.getDisplay(this);
d.setCurrent(mapTextureCanvas);
}
 
public void startApp(){
}
 
public void pauseApp(){
}
 
public void destroyApp(boolean unconditional){
}
}
 
class mapTextureCanvasextends GameCanvas implements Runnable{
 
private MIDlet midlet;
 
private Graphics3D g3d;// Графический объект для рендеринга мира.
private World world;// Это главный мир в сцене.
private Camera camera;// Камера для сцены
private Mesh plane;// Плоскость
 
private Graphics3D texg3d;
private Mesh texMesh;
private World texWorld;// Этот мир будем использовать для рендеринга в Image2D
private Camera texCamera;
 
private Image2D sceneTexture=null;// 3D текстура для плоскости
private Texture2D texture;// Текстура для пирамиды
 
private void doTexture(){
 
sceneTexture=new Image2D(Image2D.RGB,64,64);
 
texg3d= Graphics3D.getInstance();
texWorld=new World();
 
texCamera=new Camera();
texWorld.addChild(texCamera);// Помещаем камеру в мир
 
float w= getWidth();
float h= getHeight();
 
texCamera.setPerspective(60.0f, w/ h, 0.1f, 150f);
texWorld.setActiveCamera(texCamera);
 
Background bg=new Background();
try{
Image texImg= Image.createImage("/bgImage.png");
bg.setImage(new Image2D(Image2D.RGB, texImg));
}catch(Exception e){}
 
texWorld.setBackground(bg);
 
texMesh= createpyramid();
texMesh.postRotate(45.0f, 0.5f, 1.0f, 0.0f);
texMesh.translate(0.0f, 0.0f,-5.0f);
texWorld.addChild(texMesh);
}
 
public mapTextureCanvas(MIDlet m){
super(false);
 
midlet= m;
setFullScreenMode(true);
 
doTexture();
 
g3d= Graphics3D.getInstance();
world=new World();
 
camera=new Camera();
world.addChild(camera);// Помещаем камеру в мир.
 
float w= getWidth();
float h= getHeight();
 
// Создаем изометрическую матрицу проекций и устанавливаем ее в качестве активной.
camera.setPerspective(60.0f, w/ h, 0.1f, 150f);
camera.translate(0.0f, 0.0f, 0.0f);
world.setActiveCamera(camera);
 
plane= createPlane();
world.addChild(plane);
plane.translate(0.0f, 0.0f,-5.0f);
Background bg=new Background();
bg.setColor(0x000000);
world.setBackground(bg);
 
Thread t=new Thread(this);
t.start();
}
 
public void draw3D(Graphics g){
 
try{
texg3d.bindTarget(sceneTexture);// Связываем Image2D с графическим объектом
texg3d.render(texWorld);// выполняем рендеринг пирамиды в Image2D
}finally{
texg3d.releaseTarget();
}
 
try{
g3d.bindTarget(g);// Указываем, что Image2D будем использовать
// в качестве цели Graphics3D
g3d.render(world);// Выполняем рендеринг мира
}finally{
g3d.releaseTarget();
}
}
 
private void draw2D(Graphics g){
g.setColor(0xFFFFFF);
g.drawString("Exit",3, getHeight(), Graphics.LEFT| Graphics.BOTTOM);
}
 
protected void keyPressed(intkey){
 
switch(key){
case-3:
break;
case-4:
break;
case-6:
midlet.notifyDestroyed();
break;
case-7:
break;
}
}
 
public void run(){
Graphics g= getGraphics();
 
while(true){
 
texMesh.postRotate(3.0f, 0.0f, 1.0f, 0.0f);// rotate the pyramid
plane.postRotate(3.0f, 0.0f, 1.0f, 0.0f);// rotate the plane
draw3D(g);
draw2D(g);
flushGraphics();
 
try{
Thread.sleep(10);
}catch(Exception e){}
}
}
 
 
public Mesh createPlane(){
int WIDTH=21, HEIGHT=2;
 
short POINTS[]=new short[]{-1,-1,0,
1,-1,0,
1,1,0,
-1,1,0};
 
short TEXTURES[]=new short[]{0,255,
255,255,
255,0,
0,0};
 
int INDICES[]=new int[]{0,1,3,2};
int[] LENGTHS=new int[]{4};
 
VertexArray POSITIONS_ARRAY, TEXTURE_ARRAY, COLOR_ARRAY;
IndexBuffer INDEX_BUFFER;
 
// инициализируем общие массивы
POSITIONS_ARRAY=new VertexArray(POINTS.length/3,3,2);
POSITIONS_ARRAY.set(0, POINTS.length/3, POINTS);
TEXTURE_ARRAY=new VertexArray(TEXTURES.length/2,2,2);
TEXTURE_ARRAY.set(0, TEXTURES.length/2, TEXTURES);
INDEX_BUFFER=new TriangleStripArray(INDICES, LENGTHS);
 
VertexBuffer vertexBuffer=new VertexBuffer();
vertexBuffer.setPositions(POSITIONS_ARRAY, 1.0f,null);
vertexBuffer.setTexCoords(0, TEXTURE_ARRAY, 1.0f/255.0f,null);
Mesh mesh=new Mesh(vertexBuffer, INDEX_BUFFER,null);
 
Appearance appearance=new Appearance();
PolygonMode pm=new PolygonMode();
pm.setCulling(PolygonMode.CULL_NONE);
appearance.setPolygonMode(pm);
 
Image texImg;
try{
Texture2D texture1=new Texture2D(sceneTexture);
texture1.setBlending(Texture2D.FUNC_REPLACE);
texture1.setWrapping(Texture2D.WRAP_CLAMP, Texture2D.WRAP_CLAMP);
texture1.setFiltering(Texture2D.FILTER_NEAREST, Texture2D.FILTER_NEAREST);
 
appearance.setTexture(0, texture1);
 
}catch(Exception e){
System.out.println("Failed to create texture");
}
 
mesh.setAppearance(0, appearance);
 
return mesh;
}
 
private Mesh createpyramid(){
 
// Задаем координаты вершины пирамиды. x, y, z
short[]POINTS=new short[]{-1,-1,1,1,-1,1,0,1,0,// фронтальная грань
1,-1,1,1,-1,-1,0,1,0,// правая
1,-1,-1,-1,-1,-1,0,1,0,// задняя
-1,-1,-1,-1,-1,1,0,1,0,// левая
-1,-1,1,1,-1,1,1,-1,-1,// нижняя правая
-1,-1,1,1,-1,-1,-1,-1,-1};// нижняя левая
 
// Текстурные координаты масштабируются в методе setTextCoords так,
//что принимают значения от 0 до 1
short[]TEXTURES=new short[]{0,255,255,255,127,0,
0,255,255,255,127,0,
0,255,255,255,127,0,
0,255,255,255,127,0,
0,0,255,0,255,255,
0,0,255,255,0,255};
 
// Задаем последовательность точек, образующих грани.
int[]INDICES=new int[]{0,1,2,// фронтальная грань
3,4,5,// правая
6,7,8,// задняя
9,10,11,// левая
12,13,14,// нижняя правая
15,16,17};// нижняя левая
 
// Длина каждой последовательности в массиве индексов.
int[]LENGTH=new int[]{3,3,3,3,3,3};// пирамида сформирована шестью треугольниками
VertexArray POSITION_ARRAY, TEXTURE_ARRAY;
IndexBuffer INDEX_BUFFER;
 
// Создаеv VertexArray, который используется VertexBuffer
POSITION_ARRAY=new VertexArray(POINTS.length/3,3,2);
POSITION_ARRAY.set(0, POINTS.length/3, POINTS);
TEXTURE_ARRAY=new VertexArray(TEXTURES.length/2,2,2);
TEXTURE_ARRAY.set(0, TEXTURES.length/2, TEXTURES);
INDEX_BUFFER=new TriangleStripArray(INDICES, LENGTH);
 
// VertexBuffer содержит ссылки на массивы VertexArrays, в которых находятся координаты
// точек, цвета, нормали, и текстурные координаты для набора вершин.
VertexBuffer vertexBuffer=new VertexBuffer();
vertexBuffer.setPositions(POSITION_ARRAY, 1.0f,null);
vertexBuffer.setTexCoords(0, TEXTURE_ARRAY,(1.0f/255.0f),null);
vertexBuffer.setTexCoords(1, TEXTURE_ARRAY,(1.0f/255.0f),null);
// Создайте трехмерный объект
Mesh mesh=new Mesh(vertexBuffer, INDEX_BUFFER,null);
 
 
// Набор компонент объекта, определяющих атрибуты рендеринга сетки
Appearance appearance=new Appearance();
 
PolygonMode polygonMode=new PolygonMode();
polygonMode.setPerspectiveCorrectionEnable(true);
 
// Используем CULL_BACK (отсечение задних поверхностей) для повышения производительности
polygonMode.setCulling(PolygonMode.CULL_BACK);
 
appearance.setPolygonMode(polygonMode);
 
Image texImg;
try{
texImg= Image.createImage("/texture2.png");
texture=new Texture2D(new Image2D(Image2D.RGB, texImg));
texture.setWrapping(Texture2D.WRAP_CLAMP, Texture2D.WRAP_CLAMP);
texture.setBlending(Texture2D.FUNC_MODULATE);
texture.setFiltering(Texture2D.FILTER_NEAREST, Texture2D.FILTER_NEAREST);
 
appearance.setTexture(0, texture);
}catch(Exception e){
System.out.println("Failed to create texture");
}
 
mesh.setAppearance(0, appearance);// Присваиваем установленные атрибуты 3D объекту
return mesh;
}
}



Автор:Oscar Vivall
Перевод:aRix.




Наши соцсети

Подписаться Facebook Подписаться Вконтакте Подписаться Twitter Подписаться Google Подписаться Telegram

Популярное

Ссылки

Новости [1] [2] [3]... Android/ iOS/ J2ME[1] [2] [3]) Android / Архив

Рейтинг@Mail.ru Яндекс.Метрика
MobiLab.ru © 2005-2018
При использовании материалов сайта ссылка на www.mobilab.ru обязательна