Java-Gaming.org    
Featured games (91)
games approved by the League of Dukes
Games in Showcase (576)
games submitted by our members
Games in WIP (497)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Pulling texture tiles off a 'master texture'    (Read 1990 times)
0 Members and 1 Guest are viewing this topic.
zahl2001
Guest
« Posted 2004-07-02 13:11:19 »

After reading the previous good advice, I got all of my texturing problems fixed, and then I decided to take a 'better' approach toward texturing my lanscape, which caused more problems.

Heres what happened:
1) For a test, decide to use only 4 textures in landscape
2) Make a 256 X 256 image for each texture.
3) Use those to construct one 512 X 512 image.
4) Turn the large image into a texture.
5) Using tex coords, pull sections as needed.
6) For better appearance, use linear type filtering,
   thereby causing lines to appear in an all NEW way
   at texture borders in scene by averaging in pixels
   from OTHER tiles bordering the tile I want, which
   creates a much WORSE appearance.

How can I get this setup to allow linear type filtering without having to bind multiple textures during runtime, which is what I was trying to avoid?

Thanks,

Zahl
Offline Ken Russell

JGO Coder




Java games rock!


« Reply #1 - Posted 2004-07-16 23:59:34 »

I think you should alter your texture coordinates to have the edges of the tiles end up being in the middle of a texel instead of at its edge. Take a look at the source code of the Grand Canyon demo at http://java.sun.com/products/jfc/tsc/articles/jcanyon/ ; I believe it does something like this.
zahl2001
Guest
« Reply #2 - Posted 2004-07-17 00:52:50 »

Thank you sir.

I didn't know such a thing was possible, but it sounds promising...I'll start digging tomorrow.

Zahl
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
zahl2001
Guest
« Reply #3 - Posted 2004-07-18 01:14:00 »

If anyone happens to read this, it turns out that Ken Russell's suggestion dramatically improved the situation. Now the texture tiles look perfect until the camera gets very far away, and then lines appear in the terrain again. This only happens when mipmapping is used. It's annoying that it isn't perfect, but for all I know the lines could be caused by something totally unrelated to the issue that started this thread.

Anyhow...things look pretty good.

Zahl
Offline Mithrandir

Senior Member




Cut from being on the bleeding edge too long


« Reply #4 - Posted 2004-07-18 03:01:55 »


You've stated you're using mipmapping. Are you having OpenGL generate those for you? If so, that's going to be the problem. Mipmaps do their own filtering of the images as they create progressively smaller versions.  It's most likely that as they're sampling the primary image, that the pixel samples are coming from far further in the parent image than you're imagining. The only real effective solution to remove this is to generate your own mipmaps by hand.

If you must have it automated, then if you want to do a lot of extra work,  the following approach will work reasonably well.

Start by creating the sub images 2 pixesl smaller in each dimension - so 254x254

Copy those onto the large texture using the same centerpoint as before - but now you have a 1-pixel wide border around them each.

For each sub image, copy the border row of pixels off the main image to the empty row/column beside it. Use one of the Java2D image filtering ops while copying the values across.

That now gives you a 2-pixel wide border that is pre-blended before the mipmapping gets to it and munges it all again. It should smooth out those edges a bit better, with little visual cost at the close range viewing.

The site for 3D Graphics information http://www.j3d.org/
Aviatrix3D JOGL Scenegraph http://aviatrix3d.j3d.org/
Programming is essentially a markup language surrounding mathematical formulae and thus, should not be patentable.
zahl2001
Guest
« Reply #5 - Posted 2004-07-18 14:18:30 »

The mipmaps are indeed being created by OpenGL.  I've never tried creating them myself, but I will look in to it soon.  

Thanks for the info Smiley

Zahl
Offline Mithrandir

Senior Member




Cut from being on the bleeding edge too long


« Reply #6 - Posted 2004-07-18 16:12:02 »

I had another thought too - what are your min and mag filter settings? That may help you blur out the edges by playing with those if you are currently running standard settings.  Since you have mipmaps, the trilinear filtering settings like GL_LINEAR_MIPMAP_LINEAR will help a lot too.  

The site for 3D Graphics information http://www.j3d.org/
Aviatrix3D JOGL Scenegraph http://aviatrix3d.j3d.org/
Programming is essentially a markup language surrounding mathematical formulae and thus, should not be patentable.
zahl2001
Guest
« Reply #7 - Posted 2004-07-18 16:32:10 »

Mag filter:
   set to GL_LINEAR and gives perfect results.

Min filter:
   1) GL_NEAREST or GL_LINEAR gives perfect results.
   2) GL_NEAREST_MIPMAP_LINEAR gives perfect results
       until you get a fair distance away, then modest
       cracks appear.
   3) GL_LINEAR_MIPMAP_LINEAR gives heavy cracks at
       short distances and seems to get worse as the
       distance increases.
   4) GL_NEAREST_MIPMAP_NEAREST gives the same
       results as GL_NEAREST_MIPMAP_LINEAR
   5) GL_LINEAR_MIPMAP_NEAREST gives the same
       results as GL_LINEAR_MIPMAP_LINEAR.


NOTE: hand-made mipmaps have not been implemented
          yet.
Offline tom
« Reply #8 - Posted 2004-07-18 19:58:10 »

I think it would be better if you did not merge the textures. There are other ways that will improve performance, without giving you the mipmap problems. I assume you merged the textures to reduce the number of binds?

It's better to do texture state sorting.

zahl2001
Guest
« Reply #9 - Posted 2004-07-19 00:08:35 »

You assume correctly, Tom.  Could you point me toward some info on texture state sorting?

[edit] Now I think I remember you discussing this topic in a previous thread I started. If I remember correctly, the goal was to organize the polygons into groups based on the texture they used so that the particular texture would only have to be bound once for the whole lot.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Mithrandir

Senior Member




Cut from being on the bleeding edge too long


« Reply #10 - Posted 2004-07-19 05:55:01 »

Hmmm... state sorting. Often spoken about, but never really put down into words.  As such, it is somewhat of a "black art"  even though it shouldn't be.

State sorting is about minimising the number of state changes that go down the OpenGL pipeline by grouping collections of similar objects together.  Some state changes are more expensive than others. For example, turning on and off depth buffer writing is far less expensive than turning on or off a light.  What you need to do then, is to work out what state is more expensive than another and then sort your objects accordingly.

Of course, that leaves the question of "well how do I sort?".  Sorting requires that you have something to sort. Since this is an object-oriented language, sorting collections of objects is a good idea. (well, duh...).  How you decide to sort them is a long and involved process.  Every one that I've seen done in Java ends up using a wrapper object that implements the Comparable interface.
Why? Well that allows you to make use of the java.util.Arrays method called sort().  That simple method makes use of the most efficient sorting algorithm for this task - an insertion sort[1].

The Comparable interface has a method compareTo() which has to return negative, zero or positive.  This is the key to the state sorting.  As far as the insertion sort algorithm is concerned, when two objects are compared, it just wants to know the relative difference between them. It doesn't care for absolutes, just whether something is identical, less than or greater than another.  That makes our state sorting life much easier, because now all we need to do is evaluate our state in the current object versus the state in the object that is handed to us.  So long as the rules about that state comparison are consistent, you'll end up with a nicely sorted array at the end, that minimises state changes according to whatever rules you want.

The next thing to look at is - what does that object contain that it needs to compare so that it can give this answer of negative, zero or positive.  The simple answer is - whatever you need to compare to get the order correct.  Heh, good answer that one (and one of the most frustrating to find a decent answer on the internet or in books about).  That object must hold all of the state that is of importance to your sorting order, so that means things like textures, lights, material, buffer state handling etc etc.

At about this point, you've moved into the world of a scene graph. It may not look like it at first, but step back and you'll see that you need collections of  objects that hold info about the current texture (and all it's parameters), material state, light state etc. These are all classic objects of a scene graph architecture.  There's not much of a jump going from this up to the next level of creating grouping nodes, switches, viewpoints etc. So then, the question arises - do you really want to implement your own scene graph, or would one of the pre-rolled ones like Xith3D or Aviatrix3D save you a lot of time and effort?

Assuming you've decided to plow ahead with your own solution, in each of these objects you will now need to implement a comparison between the two states.  The good thing about the requirements is that it is very liberal so long as we keep to those basic ternary output talked about above.  The goal here is to sort things to minimise state change, and that's all. It's not about priority sorting (though that could be done too), so your decisions about what is "less than" or "greater than" another object's state can be entirely arbitrary - so long as you are always consistent.

To illustrate how this work, let's take an example of a Light that we want to state sort.  There are 3 different different light types provided by OpenGL - point, spot and directional light.  Let's say our two objects that we want to sort represent a light.  Our first decision point is based on whether we even have the same type of light.  Changing from a spotlight to a spotlight is a small state change compared to a directional light, for example.  So, at the start of our compareTo method, we have something like this:

1  
2  
3  
4  
5  
6  
7  
public int compareTo(Object o)  {
  if(o == this)
      return 0;

  Light other = (Light)o;
  if(type != l.type)
    return type < l.type ? -1 : 1;


If the objects are the same reference then obviously thety're the same.  Next, cast the incoming object to be the same as us. It's ok if you toss a ClassCastException here as the sorter is expecting that. Of course, there's a lot more infrastructure to go over the top if you want to make sure you are sorting more than just light state (remember what I said about scene graphs above?). Finally you get to the important bit - are the lights of the same type? If they are, then we need to find some other way of differentiating the two objects, so move on to the next comparison. If they are not the same, then great, we can bug out here and return a value safely.  Remember, we really don't care what value is returned, so long as it is either negative or positive, nor does it matter which order. So in this case, we've chosen to go with the natural ordering of the light type. Of course, you could have the other way around if you like, it makes absolutely no difference in the end.

From this point on, it's just more of the same - for every state that your object keeps, you need to do a comparison. Keep doing comparisons until you find something that doesn't match, or until there is nothing left to compare, and thus return zero.  For example,  here's the rest of that method:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
public int compareTo(Light l)
{
    if(l == null)
        return 1;

    if(l == this)
        return 0;

     // are we the same type of light?
    if(l.lightType != lightType)
        return lightType < l.lightType ? -1 : 1;

     if(enabled != l.enabled)
        return enabled ? 1 : -1;

     int res = compareColor3(diffuseColor, l.diffuseColor);
     if(res != 0)
         return res;

     res = compareColor3(specularColor, l.specularColor);
     if(res != 0)
         return res;

     return compareColor3(ambientColor, l.ambientColor);
}

protected int compareColor3(float[] a, float[] b)
{
    if(a[0] < b[0])
        return -1;
    else if (a[0] > b[0])
        return 1;

    if(a[1] < b[1])
        return -1;
    else if (a[1] > b[1])
        return 1;

    if(a[2] < b[2])
        return -1;
    else if (a[2] > b[2])
        return 1;

    return 0;
}


See how at each comparison point all we do is look for inequality and then assign some random value if they aren't.  

One thing that you do want to do is order your equality checks in a way that is the most efficient. Do the big checks first, such as the type of light, as this will get the biggest results fastest. Then, order the checks as you go down for things that are more and more likely to be the same. Determining that is going to take a lot of just basic knowledge about 3D graphics and your particular application.  Remember that this is an insertion sort algorithm that uses a tree-style structure where multiple comparisons are made time and again with O(n log n) time cost and thus the faster you can make a decision about the difference between two objects, the quicker you can sort.

Of course, that's the simple part, now you have to deal with the more complex issue of multiple-states within an object. Think of your terrain - you not only have a texture object, but material information, lights and the geometry itself (though geometry is not typically state sorted[2]).  If all you did was toss the individual lights, materials and textures into a single array and then tell Arrays to sort it, you'd end up with a huge mess, and nothing useful out the end. What you really need to sort on is the collection of states that work with a single large object.  That way a collection of state is going have the minimal change - it's amazing how often you end up with objects that have everything identical except one component of one object way down the bottom of the state set. That's why you see scene graphs have objects like Appearance that bundle everything together. Appearance is the complete set of states that an object can have, and thus makes a really nice object to sort with as all the comparisons that matter to your sorting algorithm will always be sorting exactly the same object type - even though the internals may be different, at least you'll have something meaningful out of the sorter.  Then, the comparisons can start doing checks like whether two appearances even have the same material set.

More in the next message....

The site for 3D Graphics information http://www.j3d.org/
Aviatrix3D JOGL Scenegraph http://aviatrix3d.j3d.org/
Programming is essentially a markup language surrounding mathematical formulae and thus, should not be patentable.
Offline Mithrandir

Senior Member




Cut from being on the bleeding edge too long


« Reply #11 - Posted 2004-07-19 06:03:57 »

For example, here's the comparison function out of the TextureUnit object in Aviatrix3D:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
public int compareTo(TextureUnit tu)
{
        if(tu == null)
            return 1;

        if(tu == this)
            return 0;

        if(texture != tu.texture)
        {
            if(texture == null)
               return -1;
            else if(tu.texture == null)
                return 1;

            int res = texture.compareTo(tu.texture);
            if(res != 0)
                return res;
        }

        // Same type of texture. Hmmmm.... let's now work on
       // the texture attributes.
       if(tatts != tu.tatts)
        {
            if(tatts == null)
                return -1;
            else if(tu.tatts == null)
                return 1;

            int res = tatts.compareTo(tu.tatts);
            if(res != 0)
                return res;
        }

        // Ah, well ok, Now let's try coordinate generation
       if(coordGen != tu.coordGen)
        {
            if(coordGen == null)
                return -1;
            else if(tu.coordGen == null)
                return 1;

            int res = coordGen.compareTo(tu.coordGen);
            if(res != 0)
                return res;
        }

        // Gah! Matrix time now as that's the only thing left
       if(validMatrix != tu.validMatrix)
            return validMatrix ? 1 : -1;

        for(int i = 0; i < 16; i++)
        {
            if(texTransform[i] != tu.texTransform[i])
                return texTransform[i] < tu.texTransform[i] ? -1 : 1;
        }

        return 0;
    }


See how at this high level all you care about is whether the two objects being compared even have the same objects set, and if they don't, to do a comparison on them.  This can be repeated right down the chain of object types that you're working with.

Now you've got the basics of a state sorting system going. There's plenty more to add, but this should be enough to get you up and running. Anything after this starts getting fairly implementation specific.

Footnotes:
[1] It appears that the only way of getting a good insertion algorithm is through the use of the comparison-based algorithms. I've been searching for a long time to see if I could come up with a good way of using the one of the linear sorting algorithms such as a radix sort, but that involves generating some sort of meaningful descriptor code with many, many units of comparison - basically a really big hash code. That's a very far from trivial setup for a generalised scene graph. However, if you have very specific objects and limited choices in what you're going to offer to the GL pipeline then it may be doable.

[2] Sometimes geometry is also sorted. An alternative to state sorting is depth sorting. By doing this, objects are sorted from front to back according to their distance from the camera. The idea of this technique is to eliminate overdraw as much as possible, rather than to minimise state changes. Thus, any objects that were definitely completely obscured by those in front would be pulled out of the rendering pipeline and not drawn (ie, a primitive form of occulusion culling). Overdraw was a problem back in the days of the old rasterisation-only video cards that had no 3D capabilities, but these days state changes are the real performance killer.

The site for 3D Graphics information http://www.j3d.org/
Aviatrix3D JOGL Scenegraph http://aviatrix3d.j3d.org/
Programming is essentially a markup language surrounding mathematical formulae and thus, should not be patentable.
zahl2001
Guest
« Reply #12 - Posted 2004-07-23 00:18:15 »

Mithrandir, I finally got around to implementing custom mipmaps, and it resolved my problems. Thanks quite a lot there...perhaps I can start doing something besides wrack my brain about textures for a change.

I'm going to print out your post on state sorting, as I'm sure that will come in handy when I have time to digest it.

Thanks again,

Zahl
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xsi3rr4x (12 views)
2014-04-15 18:08:23

BurntPizza (11 views)
2014-04-15 03:46:01

UprightPath (24 views)
2014-04-14 17:39:50

UprightPath (10 views)
2014-04-14 17:35:47

Porlus (27 views)
2014-04-14 15:48:38

tom_mai78101 (49 views)
2014-04-10 04:04:31

BurntPizza (108 views)
2014-04-08 23:06:04

tom_mai78101 (207 views)
2014-04-05 13:34:39

trollwarrior1 (176 views)
2014-04-04 12:06:45

CJLetsGame (182 views)
2014-04-01 02:16:10
List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:05:20
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!