I'm currently developing a small OpenGL game for the Android platform and I wonder if there's an easy way to render text on top of the rendered frame (like a HUD with the player´s score etc). The text would need to use a custom font also.
I've seen an example using a View as an overlay, but I don't know if I want to do that since I might want to port the game to other platforms later.
Any ideas?
Rendering text to a texture is simpler than what the Sprite Text demo make it looks like, the basic idea is to use the Canvas class to render to a Bitmap and then pass the Bitmap to an OpenGL texture:
// Create an empty, mutable bitmap
Bitmap bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_4444);
// get a canvas to paint over the bitmap
Canvas canvas = new Canvas(bitmap);
bitmap.eraseColor(0);
// get a background image from resources
// note the image format must match the bitmap format
Drawable background = context.getResources().getDrawable(R.drawable.background);
background.setBounds(0, 0, 256, 256);
background.draw(canvas); // draw the background to our bitmap
// Draw the text
Paint textPaint = new Paint();
textPaint.setTextSize(32);
textPaint.setAntiAlias(true);
textPaint.setARGB(0xff, 0x00, 0x00, 0x00);
// draw the text centered
canvas.drawText("Hello World", 16,112, textPaint);
//Generate one texture pointer...
gl.glGenTextures(1, textures, 0);
//...and bind it to our array
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
//Create Nearest Filtered Texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
//Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
//Use the Android GLUtils to specify a two-dimensional texture image from our bitmap
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
//Clean up
bitmap.recycle();
The Android SDK doesn't come with any easy way to draw text on OpenGL views. Leaving you with the following options.
Place a TextView over your SurfaceView. This is slow and bad, but the most direct approach.
Render common strings to textures, and simply draw those textures. This is by far the simplest and fastest, but the least flexible.
Roll-your-own text rendering code based on a sprite. Probably second best choice if 2 isn't an option. A good way to get your feet wet but note that while it seems simple (and basic features are), it get's harder and more challenging as you add more features (texture-alignment, dealing with line-breaks, variable-width fonts etc.) - if you take this route, make it as simple as you can get away with!
Use an off-the-shelf/open-source library. There are a few around if you hunt on Google, the tricky bit is getting them integrated and running. But at least, once you do that, you'll have all the flexibility and maturity they provide.
I've written a tutorial that expands on the answer posted by JVitela. Basically, it uses the same idea, but instead of rendering each string to a texture, it renders all characters from a font file to a texture and uses that to allow for full dynamic text rendering with no further slowdowns (once the initialization is complete).
The main advantage of my method, compared to the various font atlas generators, is that you can ship small font files (.ttf .otf) with your project instead of having to ship large bitmaps for every font variation and size. It can generate perfect quality fonts at any resolution using only a font file :)
The tutorial includes full code that can be used in any project :)
According to this link:
http://code.neenbedankt.com/how-to-render-an-android-view-to-a-bitmap
You can render any View to a bitmap. It's probably worth assuming that you can layout a view as you require (including text, images etc.) and then render it to a Bitmap.
Using JVitela's code above you should be able to use that Bitmap as an OpenGL texture.
Take a look at CBFG and the Android port of the loading/rendering code. You should be able to drop the code into your project and use it straight away.
CBFG - http://www.codehead.co.uk/cbfg
Android loader - http://www.codehead.co.uk/cbfg/TexFont.java
I looked at the sprite text example and it looks awfully complicated for such a task, I considered rendering to a texture too, but I'm worried about the performance hit that might cause.
I might just have to go with a view instead and worry about porting when it's time to cross that bridge :)
IMHO there are three reasons to use OpenGL ES in a game:
Avoid differences between mobile platforms by using an open standard;
To have more control of the render process;
To benefit from GPU parallel processing;
Drawing text is always a problem in game design, because you are drawing things, so you cannot have the look and feel of a common activity, with widgets and so on.
You can use a framework to generate Bitmap fonts from TrueType fonts and render them. All the frameworks I've seen operate the same way: generate the vertex and texture coordinates for the text in draw time. This is not the most efficient use of OpenGL.
The best way is to allocate remote buffers (vertex buffer objects - VBOs) for the vertices and textures early in code, avoiding the lazy memory transfer operations in draw time.
Keep in mind that game players don't like to read text, so you won't write a long dynamically generated text. For labels, you can use static textures, leaving dynamic text for time and score, and both are numeric with a few characters long.
So, my solution is simple:
Create texture for common labels and warnings;
Create texture for numbers 0-9, ":", "+", and "-". One texture for each character;
Generate remote VBOs for all positions in the screen. I can render static or dynamic text in that positions, but the VBOs are static;
Generate just one Texture VBO, as text is always rendered one way;
In draw time, I render the static text;
For dynamic text, I can peek at the position VBO, get the character texture and draw it, a character at a time.
Draw operations are fast, if you use remote static buffers.
I create an XML file with screen positions (based on screen's diagonal percentage) and textures (static and characters), and then I load this XML before rendering.
To get a high FPS rate, you should avoid generating VBOs at draw time.
Look at the "Sprite Text" sample in the GLSurfaceView samples.
If you insist on using GL, you could render the text on to textures. Assuming that most of the HUD is relatively static, you shouldn't have to load the textures to texture memory too often.
Take a look at CBFG and the Android port of the loading/rendering
code. You should be able to drop the code into your project and use it
straight away.
CBFG
Android loader
I have problems with this implementation. It displays only one character, when I try do change size of the font's bitmap (I need special letters) whole draw fails :(
I have been looking for this for a few hours, this was the first article i came accross and although it has the best answer, the most popular answers i think are off the mark. Certainly for what i needed.
weichsel's and shakazed's answers were right on the button but a bit obscured in the articles.
To put you right to the project. Here:
Just create a new Android project based on existing sample. Choose ApiDemos:
Look under the source folder
ApiDemos/src/com/example/android/apis/graphics/spritetext
And you will find everything you need.
For static text:
Generate an image with all words used on your PC (For example with GIMP).
Load this as a texture and use it as material for a plane.
For long text that needs to be updated once in a while:
Let android draw on a bitmap canvas (JVitela's solution).
Load this as material for a plane.
Use different texture coordinates for each word.
For a number (formatted 00.0):
Generate an image with all numbers and a dot.
Load this as material for a plane.
Use below shader.
In your onDraw event only update the value variable sent to the shader.
precision highp float;
precision highp sampler2D;
uniform float uTime;
uniform float uValue;
uniform vec3 iResolution;
varying vec4 v_Color;
varying vec2 vTextureCoord;
uniform sampler2D s_texture;
void main() {
vec4 fragColor = vec4(1.0, 0.5, 0.2, 0.5);
vec2 uv = vTextureCoord;
float devisor = 10.75;
float digit;
float i;
float uCol;
float uRow;
if (uv.y < 0.45) {
if (uv.x > 0.75) {
digit = floor(uValue*10.0);
digit = digit - floor(digit/10.0)*10.0;
i = 48.0 - 32.0 + digit;
uRow = floor(i / 10.0);
uCol = i - 10.0 * uRow;
fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-1.5) / devisor, uRow / devisor) );
} else if (uv.x > 0.5) {
uCol = 4.0;
uRow = 1.0;
fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-1.0) / devisor, uRow / devisor) );
} else if (uv.x > 0.25) {
digit = floor(uValue);
digit = digit - floor(digit/10.0)*10.0;
i = 48.0 - 32.0 + digit;
uRow = floor(i / 10.0);
uCol = i - 10.0 * uRow;
fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-0.5) / devisor, uRow / devisor) );
} else if (uValue >= 10.0) {
digit = floor(uValue/10.0);
digit = digit - floor(digit/10.0)*10.0;
i = 48.0 - 32.0 + digit;
uRow = floor(i / 10.0);
uCol = i - 10.0 * uRow;
fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-0.0) / devisor, uRow / devisor) );
} else {
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
}
} else {
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
}
gl_FragColor = fragColor;
}
Above code works for a texture atlas where numbers start from 0 at the 7th column of the 2nd row of the font atlas (texture).
Refer to https://www.shadertoy.com/view/Xl23Dw for demonstration (with wrong texture though)
In the OpenGL ES 2.0/3.0 you can also combining OGL View and Android's UI-elements:
public class GameActivity extends AppCompatActivity {
private SurfaceView surfaceView;
#Override
protected void onCreate(Bundle state) {
setContentView(R.layout.activity_gl);
surfaceView = findViewById(R.id.oglView);
surfaceView.init(this.getApplicationContext());
...
}
}
public class SurfaceView extends GLSurfaceView {
private SceneRenderer renderer;
public SurfaceView(Context context) {
super(context);
}
public SurfaceView(Context context, AttributeSet attributes) {
super(context, attributes);
}
public void init(Context context) {
renderer = new SceneRenderer(context);
setRenderer(renderer);
...
}
}
Create layout activity_gl.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
tools:context=".activities.GameActivity">
<com.app.SurfaceView
android:id="#+id/oglView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView ... />
<TextView ... />
<TextView ... />
</androidx.constraintlayout.widget.ConstraintLayout>
To update elements from the render thread, can use Handler/Looper.
Related
I am experiencing an issue on Android with OpenGL ES 3.1. I wrote an application that shows a liquid falling down from the top of the screen. This liquid is made of many particles that are a bit transparent, but the color using alpha blending are displayed differently on another phone.
The color of every drop is defined as follow:
private int particleColor = Color.argb(50, 0, 172, 231);
Each particle color is stored in a buffer:
private ByteBuffer colorBuffer = ByteBuffer.allocateDirect(MAX_PARTICLES * PARTICLE_COLOR_COUNT).order(ByteOrder.nativeOrder());
And this buffer is passed to the OpenGL entity to be drawn:
/**
* Binds the data to OpenGL.
* #param program as the program used for the binding.
* #param positionBuffer as the position buffer.
* #param colorBuffer as the color buffer.
*/
public void bindData(LiquidShaderProgram program, ByteBuffer positionBuffer, ByteBuffer colorBuffer){
glVertexAttribPointer(program.getPositionAttributeLocation(), POSITION_COMPONENT_COUNT, GL_FLOAT, false, POSITION_COMPONENT_COUNT * OpenGLUtils.BYTE_PER_FLOAT, positionBuffer);
glEnableVertexAttribArray(program.getPositionAttributeLocation());
glVertexAttribPointer(program.getColorAttributeLocation(), COLOR_COMPONENT_COUNT, GL_UNSIGNED_BYTE, true, COLOR_COMPONENT_COUNT, colorBuffer);
glEnableVertexAttribArray(program.getColorAttributeLocation());
}
The rendering is down by calling this function:
/**
* Render the liquid.
* #param particleCount as the particle count.
*/
public void draw(int particleCount) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDrawArrays(GL_POINTS, 0, particleCount);
glDisable(GL_BLEND);
}
The fragment shader just draw the color that it receives:
precision mediump float;
varying vec4 v_Color;
void main() {
if (length(gl_PointCoord - vec2(0.5)) > 0.5) {
discard;
} else {
gl_FragColor = v_Color;
}
}
It works very well on one phone (Nexus 5X):
But on another phone (Galaxy S10), with the exact same code, the color is not the same:
Does anyone has any idea about a way to solve this issue? I would like to display the correct color on the second phone as well.
I finally understood the issue and found the solution, after reading A LOT of documentation and browsing the web for many hours.
It looks like, on Android, the alpha premultiplication is managed by the framework while OpenGL and the native code have to manage it manually ( I still don't understand why it worked correctly on some phone and not on other phones ). But after changing the blending function and performing alpha premultiplication in the fragment shader, the problem was fixed.
The correct blending function to use is the following one:
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
Using this function ensure that the colors are the same on all phones, but that's not enough because the colors are not correct. To make it perfect, alpha premultiplication must be performed in the fragment shader:
gl_FragColor = vec4(v_Color.x * v_Color.w, v_Color.y * v_Color.w, v_Color.z * v_Color.w, v_Color.w);
After doing that, I was able to display the correct colors on all phones.
That's my understanding of the problem and the fix I found. If someone has a better explanation, I would be happy to hear it, otherwise I hope it will help someone.
I am using OpenGL ES version 3 for my android game and have implemented instancing. It works well IF I use a polygon of the same size/dimension that is identical vertices. I can jump to different UV-coordinates of the texture atlas if I want to create change the sprites state for every frame.
v_TexCoordinate = a_TexCoordinate + uvCoordsOffset[gl_InstanceID];
that is .. I just change the texture coordinates with a uniform-vec which consists of offset coordinates.
BUT - here comes the issue.
What if I want to do the same but with sprites that have different dimensions?
in the drawcall ...
GLES30.glDrawElementsInstanced(GLES30.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, indexOffset, nFallingObj);
I can only send one polygon, that is the green dinosaur vertices in the screenshot. I have this as base polygon and I want to get to the RED dinosaur of the atlas. I can do this easily with texture offset as described above BUT you see how it becomes? the polygon of the green dinosaur is used but I want to be changed as of the red dinosaurs.
Is there any easy solution to this issue?
thanks in advance!!!
some source-code
the draw-method
public void drawFallingObjects() {
GLES30.glUseProgram(mProgramHandle);
GLES30.glEnableVertexAttribArray(mPositionHandle);
GLES30.glVertexAttribPointer(mPositionHandle, CreateGLContext.POSITION_DATA_SIZE, GLES20.GL_FLOAT, false, CreateGLContext.STRIDE, 0);
GLES30.glEnableVertexAttribArray(mTextureCoordinateHandle);
GLES30.glVertexAttribPointer(mTextureCoordinateHandle, CreateGLContext.TEXTURE_COORDINATE_DATA_SIZE, GLES20.GL_FLOAT, false,
CreateGLContext.STRIDE, CreateGLContext.POSITION_DATA_SIZE * CreateGLContext.BYTES_PER_FLOAT);
GLES30.glUniform2fv(uvCoordsOffsetLoc, nFallingObj, uvOffsetVec, 0);
GLES30.glUniformMatrix4fv(mMVPMatrixHandle, nFallingObj, false, mMVPMatrixMajor, 0);
GLES30.glDrawElementsInstanced(GLES30.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, indexOffset, nFallingObj);
}
vertex-shader code
void main()
{
v_Color = a_Color;
v_TexCoordinate = a_TexCoordinate + uvCoordsOffset[gl_InstanceID];
gl_Position = u_MVPMatrix[gl_InstanceID] * a_Position;
}
What if I want to do the same but with sprites that have different
dimensions?
Your MVP matrix can encode scale and skew, which is all you need to adjust the on-screen sprite size.
I am drawing a triangle in OpenGL like:
MyGLRenderer( )
{
fSampleVertices = ByteBuffer.allocateDirect( fSampleVerticesData.length * 4 )
.order ( ByteOrder.nativeOrder( ) ).asFloatBuffer( );
fSampleVertices.put( fSampleVerticesData ).position ( 0 );
Log.d( TAG, "MyGLRender( )" );
}
private FloatBuffer fSampleVertices;
private final float[] fSampleVerticesData =
{ .8f, .8f, 0.0f, -.8f, .8f, 0.0f, -.8f, -.8f, 0.0f };
public void onDrawFrame( GL10 unused )
{
GLES30.glViewport ( 0, 0, mWidth, mHeight );
GLES30.glClear ( GLES30.GL_COLOR_BUFFER_BIT );
GLES30.glUseProgram ( dProgramObject1 );
GLES30.glVertexAttribPointer ( 0, 3, GLES30.GL_FLOAT, false, 0, fSampleVertices );
GLES30.glEnableVertexAttribArray ( 0 );
GLES30.glDrawArrays( GLES30.GL_TRIANGLES, 0, 3 );
//Log.d( TAG, "onDrawFrame( )" );
}
So since I have experimented with the co-ordinates it doesn't take long to figure out that the visible area of the screen
is between -1,1. So then the triangle takes up 80% of the screen. As well I have determined that the pixel dimensions of my
GLSurfaceView are 2560 in width and 1600 in height.
So then given a triangle with these pixel based co-ordinates (fBoardOuter):
1112.0f
800.0f
0.0f
-1280.0f
800.0f
0.0f
-1280.0f
-800.0f
0.0f
I have to either convert those pixel co-ordinates to something between -1,1 or find out a way to have gl convert those co-ordinates
at the time they are drawn? Since I am very new to OpenGL I am looking for some guidance to do this?
My vertex shader is like:
String sVertexShader1 =
"#version 300 es \n"
+ "in vec4 vPosition; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = vPosition; \n"
+ "} \n";
Would I be correct then in saying that a pixels based system would be called world co-ordinates? What I am trying to do right now is just some 2D drawing for a board game.
I've discovered that Android has this function:
orthoM(float[] m, int mOffset, float left, float right, float bottom, float top, float near, float far)
However there is nothing in the documentation I've read so far that explain the usage of the matrix of how a float[] with pixel co-ordinates can be transformed to normalized co-ordinates with that matrix in GLES30.
I've also found the documentation here:
http://developer.android.com/guide/topics/graphics/opengl.html
Based off the documentation I have tried to create an example:
http://pastebin.com/5PTsfSdz
In the pastebin example fSampleVertices I thought would be much smaller and at the center of the screen but it isn't it's still almost the entire screen and fBoardOuter just shows me a black screen if I try to put it into glDrawArray.
You will probably need to find a book or some good tutorials to get a strong grasp on some of these concepts. But since there some specific items in your question, I'll try and explain them as well as I can within this format.
The coordinate system you discovered, where the range is [-1.0, 1.0] in the x- and y coordinate directions, is officially called Normalized Device Coordinates, often abbreviated as NDC. Which is very similar to the name you came up with, so some of the OpenGL terminology is actually very logical. :)
At least as long as you're dealing with 2D coordinates, this is the coordinate range your vertex shader needs to produce. I.e. the coordinates you assign to the built-in gl_Position variable need to be within this range to be visible in the output. Things gets slightly more complicated if you're dealing with 3D coordinates and are applying perspective projections, but we'll skip over that part for now.
Now, as you already guessed, you have two main options if you want to specify your coordinates in a different coordinate system:
You transform them to NDC in your code before you pass them to OpenGL.
You have OpenGL apply transformations to your input coordinates.
Option 2 is clearly the better one, since GPUs are very efficient at performing this job.
On a very simple level, this means that you modify the coordinates in your vertex shader. If you look at your very simple first vertex shader:
in vec4 vPosition;
void main()
{
gl_Position = vPosition;
}
you get the coordinates provided by your app code in the vPosition input variable, and you assign exactly he same coordinates to the vertex shader output gl_Position.
If you want to use a different coordinate system, you process the input coordinates in the vertex shader code, and assign those processed coordinates to the output instead.
Modern versions of OpenGL don't really have a name for those coordinate systems anymore. There used to be "model coordinates" and "world coordinates" when some of this stuff was still hardwired into a fixed pipeline. Now that this is done with programmable shader code, those concepts are not relevant anymore from the OpenGL point of view. All it cares about are the coordinates that come out of the vertex shader. Everything that happens before that is your own business.
The canonical way of applying linear transformations, which includes the translations and scaling you need for your intended use, is by multiplying the coordinates with a transformation matrix. You already discovered the android.opengl.Matrix package that contains some utility functions for building transformation matrices if you don't want to write the (simple) code yourself.
Once you have a transformation matrix, you pass it into the vertex shader as a uniform variable, and apply the matrix in your shader code. The way this looks in the shader code is for example:
in vec4 vPosition;
uniform mat4 TransformMat;
void main()
{
gl_Position = TransformMat * vPosition;
}
To set the value of this matrix, you need to get the location of the uniform variable once after linking the shader, with prog your shader program:
GLint transformLoc = GLES20.glGetUniformLocation(prog, "TransformMat");
Then, at least once, and every time you want to change the matrix, you call:
GLES20.glUniformMatrix4fv(transformLoc, 1, GL_FALSE, mat, 0);
where mat is the matrix you either built yourself, or got from one of the utility functions in android.opengl.Matrix. Note that this call needs to be after you make the program current with glUseProgram().
In my app, there is no frustum culling, objects not seen by camera are drawn anyway. When the camera is not looking at the objects, my fps is near 60 on my android device. When it looks at the objects, my fps drops to about 15.
Therefore I think this is an issue with my pixel shader. Because I use monogame, the shader is actually written with directx shader model 3.0. Below is my texture sampler declaration and my pixel shader. (this is the only pixel shader used)
texture2D tex1;
sampler2D tex1Sampler = sampler_state
{
Texture = <tex1>;
MinFilter = Point;
MagFilter = Point;
MipFilter = Point;
AddressU = Clamp;
AddressV = Clamp;
};
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float4 color = tex2D(tex1Sampler,input.Texture);
clip(color.a - .12f);
color *= input.Tint;
return color;
}
What could be causing this FPS drop? Some other info: the texture used is size 250 x 250, and it's the only texture used in my tests.
it's not something absurd either, like a billion triangles all lined up behind each other and no back face culling enabled. It's only like 1000 small triangles in the scene, which should not be unreasonable.
removed Clip() from pixel shader and got 30 fps increase.
Now I can't really do alpha blending without sorting everything.....
I did a lot of search and nothing solved my problem. I'm both new to android and to 3d programming. I'm working on an Android project where I need to draw a 3d object on the android device using opengl es. For each pixel I have Distance value between 200 and 9000, which needs to be mapped as a Z coordinate. The object is 320x240.
The questions are:
How do I map from (x,y,z) to opengl es coordinate system? I have created a vertex array whose values are {50f, 50f, 400f, 50f, 51f, 290f, ...}. Each pixel is represented as 3 floats (x,y,z).
How can this vertex array be drawn using opengl on an android?
Is it possible to draw 320*240 pixels using OpenGl ES?
OpenGL doesn't really work well with large numbers (like anything over 10.0f, just the way it is designed). It would be better to convert your coordinates to be between -1 and 1 (i.e. normalize) than to try and make openGL use coordinates of 50f or 290f.
The reason the coordinates are normalized to between -1 and 1 is because model coordinates are only supposed to be relative to each other and not indicative of their actual dimensions in a specific game/app. The model could be used in many different games/apps with different coordinate systems, so you want all the model coordinates to be in some normalized standard form, so the programmer can then interpret in their own way.
To normalize, you loop through all your coordinates and find the value furthest from 0 i.e.
float maxValueX = 0;
float maxValueY = 0;
float maxValueZ = 0;
// find the max value of x, y and z
for(int i=0;i<coordinates.length'i++){
maxValueX = Math.max(Math.abs(coordinates[i].getX()), maxValueX);
maxValueY = Math.max(Math.abs(coordinates[i].getY()), maxValueY);
maxValueZ = Math.max(Math.abs(coordinates[i].getZ()), maxValueZ);
}
// convert all the coordinates to be between -1 and 1
for(int i=0;i<coordinates.length'i++){
Vector3f coordinate = coordinates[i];
coordinate.setX(coordinate.getX() / maxValueX);
coordinate.setY(coordinate.getY() / maxValueY);
coordinate.setZ(coordinate.getZ() / maxValueZ);
}
You only need to do this once. Assuming you are storing your data in a file, you can write a little utility program that does the above to the file and save it, rather than doing it every time you load the data into your app
Checkout the GLSurfaceView Activity in the APIDemos that ship with the Android SDK. That will give you a basic primer on how Android handles rendering through OpenGL ES. This is located in android-sdk/samples/android-10/ApiDemos. Make sure you have downloaded the 'Samples for SDK' under the given API level.
Here's a couple of resources to get you started as well:
Android Dev Blog on GLSurfaceView
Instructions on OpenGLES
Android Development Documentation on OpenGL
Hope that helps.
Adding to what James had mentioned about normalizing to [-1,1].
A little bit of code :
FIll in data in a flat array as x,y,z assuming you are using a vertex shader similar to :
"attribute vec3 coord3d;" +
"uniform mat4 transform;" +
"void main(void) {" +
" gl_Position = transform * vec4(coord3d.xyz, 1.0f);" + // size of 3 with a=1.0f for all points
" gl_PointSize = 10.0;"+
"}"
Get the attribute :
attribute_coord3d = glGetAttribLocation(program, "coord3d");
Create VBO:
glGenBuffers(1, vbo,0);
Bind
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
Put data in:
glBufferData(GL_ARRAY_BUFFER, size:SIZE_OF_ARRAY, makeFloatBuffer(FlatArray), GL_STATIC_DRAW);
where makeFloatBuffer is a function that creates a buffer:
private FloatBuffer makeFloatBuffer(float[] arr) {
ByteBuffer bb = ByteBuffer.allocateDirect(arr.length*4);
bb.order(ByteOrder.nativeOrder());
FloatBuffer fb = bb.asFloatBuffer();
fb.put(arr);
fb.position(0);
return fb;
}
Bind and Point to buffer:
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glEnableVertexAttribArray(attribute_coord3d);
glVertexAttribPointer(attribute_coord3d,
size:3,GL_FLOAT,false,stride:vertexStride, 0);
where vertexStride = num_components*Float.BYTES; in our case num_components = 3 // x,y,z.
Draw:
glDrawArrays(GL_POINTS, 0, NUM_OF_POINTS);
Disable VBO:
glDisableVertexAttribArray(attribute_coord2d);