www.jpct.net

jPCT-AE - a 3d engine for Android => Support => Topic started by: AceGIS on August 24, 2012, 06:26:26 am

Title: Multiple textures on a terrain
Post by: AceGIS on August 24, 2012, 06:26:26 am
Hi All,

I have a .ser model that I am loading onto a GLSurfaceView for an Augmented Reality app I am building. So far I am using a single texture. I would like to use different textures based on the height of the polygon in my model.

What is the best way to approach this?

Thanks in advance...
Title: Re: Multiple textures on a terrain
Post by: EgonOlsen on August 24, 2012, 02:58:25 pm
Simple and ugly:


Simple, not so ugly but maybe not applicable:


Slow and buggy on some devices:

Best solution, but a little more complex and it requires OpenGL ES 2.0:

Title: Re: Multiple textures on a terrain
Post by: Thomas. on August 24, 2012, 05:11:39 pm
And you can use alpha channel of each texture to save one more material without any performance drop. It needs just a few extra lines of code and ITextureEffect interface ;)
Title: Re: Multiple textures on a terrain
Post by: AceGIS on August 28, 2012, 12:52:57 am
Hi Egon,

Thank you for the very informative answer.

Could you please show a snippet demonstrating how I might use Simple and ugly (sharp edges are OK, jaggy edges I will have to see). Lets say I have 20 - 40 textures that I want to load only when required (runtime), how would I then check each polygon in the camera FOV and draw the correct texture? OR would it be more efficient (for a static model) to load all textures for the entire model based on polygon height?

I am currently using OpenGL ES 2.0, therefore could you please also show a snippet using the Best solution method. My terrain model will be the only object in my world. I am pretty new to 3D modelling. Could you please explain splatting textures?? Oh and how to use a custom shader??

Thanks again Egon.
Title: Re: Multiple textures on a terrain
Post by: EgonOlsen on August 28, 2012, 08:30:12 pm
Why do you need 20-40 textures? That's quite a lot and unless they are very small, you'll run into memory problems with that. Anyway, you can't assign them dynamically at runtime (well, you can...but it's complicated and kills performance, so there's no point in doing it). Just assign them at build time. You are creating the object anyway, so why not assign the correct texture based on the current height in the process!?

A custom shader can be created by creating an instance of GLSLShader and assign to an Object3D. For that, you have to write the shader code in glsl...this the shader that i'm using for the terrain:

vertex shader
Code: [Select]
attribute vec2 texture0;
attribute vec2 texture1;
attribute vec2 texture2;
attribute vec2 texture3;

uniform vec4 additionalColor;
uniform vec4 ambientColor;

uniform mat4 modelViewMatrix;
uniform mat4 modelViewProjectionMatrix;
uniform mat4 textureMatrix;

uniform float fogStart;
uniform float fogEnd;
uniform vec3 fogColor;

uniform vec3 lightPositions[8];
uniform vec3 diffuseColors[8];
uniform vec3 specularColors[8];

uniform float shininess;

attribute vec4 position;
attribute vec3 normal;

varying vec2 texCoord0;
varying vec2 texCoord1;
varying vec2 texCoord2;
varying vec2 texCoord3;

varying vec4 vertexColor;
varying vec4 fogVertexColor;

const vec4 WHITE = vec4(1.0,1.0,1.0,1.0);

void main(void)
{
texCoord0=texture0;
texCoord1=texture1*0.5;
texCoord2=texture2;
texCoord3=texture3;

vertexColor = additionalColor+ambientColor;

vec3 vVertex = vec3(modelViewMatrix * position);
vec3 normalEye   = normalize(modelViewMatrix * vec4(normal, 0.0)).xyz;
float angle = dot(normalEye, normalize(lightPositions[0] - vVertex));

if (angle > 0.0) {
vertexColor += vec4(diffuseColors[0] * angle + specularColors[0] * pow(angle, shininess),0.0);
}

vertexColor=2.0*vec4(min(WHITE, vertexColor).xyz, 0.5);

float fogWeight = clamp((-vVertex.z - fogStart) / (fogEnd - fogStart), 0.0, 1.0);
fogVertexColor = vec4(fogColor, 0.0) * fogWeight;
fogWeight=1.0-fogWeight;

vertexColor*=fogWeight;
gl_Position = modelViewProjectionMatrix * position;
}

fragment shader
Code: [Select]
precision highp float;

uniform sampler2D textureUnit0;
uniform sampler2D textureUnit1;
uniform sampler2D textureUnit2;
uniform sampler2D textureUnit3;

varying vec2 texCoord0;
varying vec2 texCoord1;
varying vec2 texCoord2;
varying vec2 texCoord3;

varying vec4 vertexColor;
varying vec4 fogVertexColor;

void main (void)
{
vec4 col0 = texture2D(textureUnit0, texCoord0);
vec4 col1 = texture2D(textureUnit1, texCoord1);
vec4 col2 = texture2D(textureUnit2, texCoord2);
vec4 col3 = col2*0.4;
vec4 blend = texture2D(textureUnit3, texCoord3);

float w1=blend.r;
float w2=blend.g;
float w3=blend.b;

gl_FragColor = vertexColor * vec4(((1.0-w1)*(1.0-w2)*(1.0-w3)*col0+col1*w1+col2*w2+col3*w3).rgb, 0.0) + fogVertexColor;
}

If you are a beginner in 3d, i suggest to stay away from shaders if possible. Anyway, a splatting texture is a texture that defines the distribution of other textures on an object based on it's own rgb values. You can see that in the fragment shader posted above. In your case, you might not need this, because you could simply use the height instead.

Title: Re: Multiple textures on a terrain
Post by: AceGIS on August 29, 2012, 05:55:57 am
Hi Egon,

OK. I think the shaders may be over my head for now.  ;)

Do you have a snippet showing how to loop through the models polygons and assign textures to different height ranges (10m - 50m = texture A, 51m - 100m = texture B, ......). I think I will be able to reduce the number of textures down to around 5 - 10.

Also, do you have any idea on how I can convert the jPCT-AE world coordinate system into Lat/Long so I can place my model where it belongs in the "real world"? I will then also need to work out how to place the jPCT-AE camera at the devices "real world" coordinate from the GPS.

In summary, my idea is to place the model in it's "real world" location, then place the camera at the GPS location to enable the user to "look" around the model by moving the device (using the compass for direction) so long as the device is in the same location as the model.

Thanks Egon.
Title: Re: Multiple textures on a terrain
Post by: Thomas. on August 29, 2012, 04:03:57 pm
Maximum number of texture layers is 4, you can not use 5-10 textures...
Title: Re: Multiple textures on a terrain
Post by: EgonOlsen on August 29, 2012, 09:50:40 pm
Maximum number of texture layers is 4, you can not use 5-10 textures...
You can. You just can't use them all on one polygon. jPCT allows you to use as many textures as you wish (and memory permits) on one object...just not more than 4 on one polygon. The object compiler takes care of the splitting and batching that it needed to render these objects.
Title: Re: Multiple textures on a terrain
Post by: EgonOlsen on August 29, 2012, 09:54:33 pm
Do you have a snippet showing how to loop through the models polygons and assign textures to different height ranges (10m - 50m = texture A, 51m - 100m = texture B, ......). I think I will be able to reduce the number of textures down to around 5 - 10.

I don't think that you have to loop through them. How are you creating the object? Based on your height map using Object3D.addTriangle or are you converting your data into some supported file format and load that? In the latter case, you can use the PolygonManager to determine the height (getTransformedVertex) and set the new texture (setPolygonTexture). Just make sure that you are doing this before calling build() or compile() on that object.

Also, do you have any idea on how I can convert the jPCT-AE world coordinate system into Lat/Long so I can place my model where it belongs in the "real world"? I will then also need to work out how to place the jPCT-AE camera at the devices "real world" coordinate from the GPS.
Sorry, no idea...
Title: Re: Multiple textures on a terrain
Post by: Thomas. on August 29, 2012, 10:23:14 pm
Maximum number of texture layers is 4, you can not use 5-10 textures...
You can. You just can't use them all on one polygon. jPCT allows you to use as many textures as you wish (and memory permits) on one object...just not more than 4 on one polygon. The object compiler takes care of the splitting and batching that it needed to render these objects.

Oh, are these data loaded from OBJ? How is it working, or how is it called? I have to find the way to define it in 3Ds max :)
Title: Re: Multiple textures on a terrain
Post by: EgonOlsen on August 29, 2012, 10:29:50 pm
Oh, are these data loaded from OBJ? How is it working, or how is it called? I have to find the way to define it in 3Ds max :)
Sorry for editing your post..it was an accident...i actually wanted to remove my typo in MY post not in your quote...now, both are fixed... ;)
Anyway, i'm not sure if i get the question. You can assign as many textures as you like and that includes textures defined in materials from obj or 3ds.
Title: Re: Multiple textures on a terrain
Post by: AceGIS on August 29, 2012, 10:33:40 pm
Hi Egon,

I am converting an Ascii GRID into a 3D Studio .3ds then serializing using the mesh serializer plugin.

So I need to access the polygon manager of my object, then using getTransformedVertex, for each vertex = some height, setPolygonTexture. BEFORE build().

Thanks again Egon..
Title: Re: Multiple textures on a terrain
Post by: AceGIS on September 02, 2012, 11:40:33 pm
Hi Egon,

I have succeeded with the Simple and ugly method. ;)

Code: [Select]
dem1 = Loader.loadSerializedObject(res.openRawResource(R.raw.jcu_lidar_gcs_0));
PolygonManager dem1PolyManager = dem1.getPolygonManager();
Logger.log("Max poly ID DEM1: " + dem1PolyManager.getMaxPolygonID());

for (int i = 0; i < dem1PolyManager.getMaxPolygonID(); i++) {
for (int j = 0; j < 3; j++) {
//Logger.log("Transformed vertex:" + i + "-" + j + " " + dem1PolyManager.getTransformedVertex(i, j).toString());
if (dem1PolyManager.getTransformedVertex(i, 0).z > 0 && dem1PolyManager.getTransformedVertex(i, 0).z < 50) {
dem1PolyManager.setPolygonTexture(i, tm.getTextureID("grey_texture"));
}

else if (dem1PolyManager.getTransformedVertex(i, 0).z > 50 && dem1PolyManager.getTransformedVertex(i, 0).z < 100) {
dem1PolyManager.setPolygonTexture(i, tm.getTextureID("green_texture"));
}

else if (dem1PolyManager.getTransformedVertex(i, 0).z > 100 && dem1PolyManager.getTransformedVertex(i, 0).z < 200) {
dem1PolyManager.setPolygonTexture(i, tm.getTextureID("blue_texture"));
}

else if (dem1PolyManager.getTransformedVertex(i, 0).z > 200 && dem1PolyManager.getTransformedVertex(i, 0).z < 300) {
dem1PolyManager.setPolygonTexture(i, tm.getTextureID("purple_texture"));
}

else if (dem1PolyManager.getTransformedVertex(i, 0).z > 300 && dem1PolyManager.getTransformedVertex(i, 0).z < 400) {
dem1PolyManager.setPolygonTexture(i, tm.getTextureID("red_texture"));
}

else {
dem1PolyManager.setPolygonTexture(i, tm.getTextureID("yellow_texture"));
}
}
}

I am now working on a way to blend the different textures to reduce the jagged edges.

Also, could you please explain how to use the tranformToGL() method. My model is in OpenGL coords, therefore it is on it's side... :o

Thanks for your help.
Title: Re: Multiple textures on a terrain
Post by: AceGIS on September 02, 2012, 11:52:49 pm
Screen shot attached showing the models orientation on load.

[attachment deleted by admin]
Title: Re: Multiple textures on a terrain
Post by: AceGIS on September 02, 2012, 11:57:02 pm
Screen shot showing correct orientation

[attachment deleted by admin]
Title: Re: Multiple textures on a terrain
Post by: AceGIS on September 06, 2012, 04:22:02 am
Hi Egon,

Disregard the transformToGL() request. The engine already applies this to my model? Is this correct?
Title: Re: Multiple textures on a terrain
Post by: EgonOlsen on September 06, 2012, 07:09:19 am
tranformToGL is meant for the case where you want to use a jPCT-Matrix directly in OpenGL, for example in a shader. You usually don't have to care about it.
Title: Re: Multiple textures on a terrain
Post by: AceGIS on September 27, 2012, 11:34:48 pm
Hi Egon,

I have made some great progress with my AR app. I finally understand the OpenGL coordinate system and have created a Lat/Long to OpenGL coordinate converter method to handle the live navigation.

I would now like to improve the rendering of my model. As you can see in the attached screen shot (you told me this would be the case) my model is jagged due to assigning a texture based on the vertex height.

I would now like to try a shader approach. I need to assign different textures based on the terrains height value. Could you please show me an example of shading a terrain using only the height values (or does the shader need x, y values also?).

[attachment deleted by admin]
Title: Re: Multiple textures on a terrain
Post by: K24A3 on September 28, 2012, 09:49:15 am
What you could do is create a thin mixed color layer between the main colors.

For example you could put a strip of Orange between Red  and Yellow to blend them in better which should relieve the harshness of the jaggies.

between 300 and 398 = Red
between 398 and 402 = Orange
between 402 and up = Yellow

...or you could simply modify the textures themselves to contain the color transition at the top and bottom of the texture.
Title: Re: Multiple textures on a terrain
Post by: EgonOlsen on September 28, 2012, 08:34:44 pm
...or you could simply modify the textures themselves to contain the color transition at the top and bottom of the texture.
That's a neat idea IMHO. You could create some large texture that contains all the colors incl. the transitions and just map u/v accordingly to the height.
Title: Re: Multiple textures on a terrain
Post by: AceGIS on October 02, 2012, 05:06:37 am
Hi Egon,

How do you mean "map u/v accordingly to the height"?

I tried adding the transition colors to the textures but the transitions are not where I expected them to be? The textures seem to be rotated on their side?

I also had the thaught that I could create a scaled/graduated jpeg containing all the colors I need and then use some algorithm to select colors based on the models height. Is this what you are suggesting Egon? How would I do this?

I also thaught I may be able to use the pixel values similar to how jPCT-AE uses the Blit class??
Title: Re: Multiple textures on a terrain
Post by: EgonOlsen on October 02, 2012, 08:11:35 pm
I also had the thaught that I could create a scaled/graduated jpeg containing all the colors I need and then use some algorithm to select colors based on the models height. Is this what you are suggesting Egon? How would I do this?
Yes, that's the idea. It the texture's orientation isn't correct, either swap u/v or rotate your texture. Anyway, the basic idea is to normalize the height, i.e. for each vertex calculate the normalized height by (height-min)/(max-min). Use the result as either u or v (depending on your texture's orientation) on that particular vertex. Do that for all vertices.
Title: Re: Multiple textures on a terrain
Post by: AceGIS on October 05, 2012, 03:43:42 am
Hi Egon,

I have normalized the height values (correctly? snippet below) to values between 0 - 1. How do I set the texture using these values? I understand the u/v as texture coords but how do I assign values from the single texture?

Code: [Select]
for (Object3D obj : models) {
PolygonManager objPolyManager = obj.getPolygonManager();
Logger.log("Max poly ID " + obj.getName() + ": " + objPolyManager.getMaxPolygonID());

// for each polygon set texture according to vertex elevation
for (int i = 0; i < objPolyManager.getMaxPolygonID(); i++) {
Logger.log("Poly num: " + i);

for (int j = 0; j < 3; j++) {
SimpleVector height = objPolyManager.getTransformedVertex(i, j);
float tempMin = (float) 2.7523;
float tempMax = (float) 555.413025;
float normHeight = (height.z - tempMin)/(tempMax - tempMin);

Logger.log("Normalised vertex height #: " + j + " - " + normHeight);
}

Thank you for your help with this task. I will endeavour to repay you some way, some day...
Title: Re: Multiple textures on a terrain
Post by: EgonOlsen on October 06, 2012, 10:03:05 am
You can use the PolygonManager to assign new texture coordinates. You already know how to access the single vertices to extract the height. You can then use this normalized height to create a new TextureInfo per polygon and assign it.
Title: Re: Multiple textures on a terrain
Post by: AceGIS on October 08, 2012, 03:26:12 am
Thanks Egon. Perfect!

I now have a scaled color applied to my terrain.  :D

Now I need to fix my onPause and onResume from my master activity... :P

[attachment deleted by admin]