jPCT-AE - a 3d engine for Android > Support

Multiple textures on a terrain

(1/5) > >>

AceGIS:
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...

EgonOlsen:
Simple and ugly:


* Use different textures per polygon based on the vertices height.
* This will create sharp and jaggy edges between the different textures.
Simple, not so ugly but maybe not applicable:


* Use one larger texture that contains the different parts and covers the whole terrain.
* Either texture the terrain with only that texture or use multi-texturing and blend it with the base texture.
* This will (depending on the texture's quality) create smooth transitions, but the result might be too coarse or blurry.
Slow and buggy on some devices:

* Render two versions of the same mesh with different textures.
* One contains the base texture, the other the upper and lower parts (i.e. rocks and sand) and use some vertex-alpha to blend to transparency in between.
* This is slow (it cuts your framerate in half) and simply doesn't work on some devices because the vertex alpha doesn't work there.
Best solution, but a little more complex and it requires OpenGL ES 2.0:


* Use multitexturing to apply ground, rocks, sand...and a splatting texture all to the same mesh.
* Use a custom shader to read from the splatting texture and mix the other textures based on that value.
* Looks good, is very flexible and runs pretty fast. You have to write the shader though.
* Related: http://www.jpct.net/forum2/index.php/topic,2912.msg21431.html#msg21431

Thomas.:
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 ;)

AceGIS:
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.

EgonOlsen:
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: ---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;
}
--- End code ---

fragment shader

--- Code: ---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;
}
--- End code ---

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.

Navigation

[0] Message Index

[#] Next page

Go to full version