How to Transition Between Skybox Textures

Started by AGP, September 22, 2011, 07:36:59 PM

Previous topic - Next topic

AGP


EgonOlsen

Either with an ITextureEffect or a blending shader, i suppose. Another option might be to use a clone of the skybox with another texture and do the blending via altering the transparency of both. But that limits the effect to two textures. Or maybe ask HRolf what he did here: http://stickmenwars2.blogspot.com/

AGP

Thanks. Is there a disadvantage to either? And speaking of shaders, could you advise me on my shader question? Your jpct e-mail address is a hit-or-miss nightmare. I ordered half a dozen glsl shader books from Amazon and I'm now waiting for them to arrive.

Very nice-looking game, by the way. I'll be sure to tell HRolf that.

EgonOlsen

The ITextureEffect-solution won't be very fast...but maybe fast enough if the texture doesn't change constantly. The shader approach is the most flexible and the multiple, blended skybox approach might suffer from zbuffer artifacts if not done right.

No idea what's the problem with my mail address...you might want to try helge.foerster@t-online.de instead. But i'm not checking that account as frequently as the other.

About the shader question: No idea. I'm not a shader expert myself and i decided for myself to limit my support regarding shaders to the technical infrastructure of the engine. I'm not going to cover all aspects of user generated shaders in this forum. I think there are better forums for this (at least i hope so...) and i simply don't have the time to do it good.

AGP

Thanks for the address, and I guess I'll have to wait for my books. If I get it to work I'll put it up on the wiki. And I don't know of a GLSL shader-specific message board, but I'd love to find one.

EgonOlsen


AGP

Thanks a lot. Now, I'm going to try all three ways you suggested. I started out with the transparency one. Should this line work:

manager.getTexture("DayLeft").setAlpha((int)(255f*percentage));

As percentage (the percentage of any given number of hours) increases, should this line not make the skybox more transparent? Because it's not working (nothing's happening, althout the percentage variable (a double) is increasing.

EgonOlsen

That would require that you trigger a new texture upload for each iteration. That's not what i meant. I meant blending two skyboxes into each other by using a simple setTransparency() on each. Make sure that the sorting is correct, i.e. you might have to set an explicit sort offset on either one or both of them.

AGP

But Object3D.setTransparency isn't well-documented. I don't know what to pass it (plus the SkyBox class isn't a subclass of Object3D).

EgonOlsen

There are some settings in Config to tweak behaviour of the transparency formula. The skybox class doesn't allow for setting a transparency ATM. But you can get the World that it uses a internally and get the skybox object from that. However, i suggest to go for the ITextureEffect solution first. If that is fast enough, it should be the much better solution.

AGP


AGP

I don't mean to sound like a nuisance, but this is as far as I got with the ITextureEffect implementation. Left to me, I would probably use Java2D and use Composite or so to "fade in" the new texture onto the awt.Image of the old one, but this can't be the right way to go. I don't even know where to start with the int arrays.


class TextureTransition implements ITextureEffect {
     private TextureManager manager;
     private int[] buffer1, buffer2;
     private int width, height;
     public TextureTransition(TextureManager manager, String texture) {
this.manager = manager;
manager.addTexture(texture, new Texture(texture));
     }
     public void apply(int[] dest, int[] source) {//Applies the effect
     }
     public boolean containsAlpha() {//If true, jPCT assumes that the alpha channel in the returned pixels is populated and treats it accordingly
return false;
     }
     public void init(Texture tex) {//called by setEffect(), so no need to call this method directly
this.buffer1 = new int[tex.getArraySize()];
this.buffer2 = new int[tex.getArraySize()];
this.width = tex.getWidth();
this.height = tex.getHeight();
     }
}

Hrolf

I used the code below. (I only used the top half of the texture). Hope it helps!
BTW horizColor means horizon colour.

import com.threed.jpct.*;
import com.threed.jpct.util.*;

public class SkyTextureEffect implements ITextureEffect
{
  public int timeOfDay=0;
  boolean isDaylight;
  boolean isNight;

  public SkyTextureEffect()
  {
  }

  public void init(Texture texture)
  {
  }

  public void apply(int[] dest, int[] src)
  {
int seaColor=0x223545;

int skyColorDay=0x5B7590;
int horizColorDay=0x929EA6;

int skyColorDawn=0x344453;
int horizColorDawn=0xD0906D;

int skyColorNight=0x0D1316;
int horizColorNight=0x374657;

int skyColor=0;
int horizColor=0;

if (timeOfDay>=0 && timeOfDay<40)
{
// just after dawn
int percentDaylight=(timeOfDay*100)/40;
skyColor=interpolateColor(skyColorDawn,skyColorDay,percentDaylight);
horizColor=interpolateColor(horizColorDawn,horizColorDay,percentDaylight);
}
else if (timeOfDay>=40 && timeOfDay<2660)
{
// daylight
if (isDaylight) return;
skyColor=skyColorDay;
horizColor=horizColorDay;
isDaylight=true;
isNight=false;
}
else if (timeOfDay>=2660 && timeOfDay<2700)
{
// dusk begins
int percentDaylight=((timeOfDay-2660)*100)/40;
skyColor=interpolateColor(skyColorDay,skyColorDawn,percentDaylight);
horizColor=interpolateColor(horizColorDay,horizColorDawn,percentDaylight);
}
else if (timeOfDay>=2700 && timeOfDay<2740)
{
// dusk ends
int percentDaylight=((timeOfDay-2700)*100)/40;
skyColor=interpolateColor(skyColorDawn,skyColorNight,percentDaylight);
horizColor=interpolateColor(horizColorDawn,horizColorNight,percentDaylight);
}
else if (timeOfDay>=2740 && timeOfDay<3560)
{
// nighttime
if (isNight) return;
skyColor=skyColorNight;
horizColor=horizColorNight;
isNight=true;
isDaylight=false;
}
else if (timeOfDay>=3560)
{
// dawn begins
int percentDaylight=((timeOfDay-3560)*100)/40;
skyColor=interpolateColor(skyColorNight,skyColorDawn,percentDaylight);
horizColor=interpolateColor(horizColorNight,horizColorDawn,percentDaylight);
}

for (int y=0;y<128;y++)
{
int color=skyColor;
if (y>124)
{
color=seaColor;//interpolateColor(horizColor,seaColor,((y-124)*100)/4);
}
else if (y>64)
{
color=interpolateColor(skyColor,horizColor,((y-64)*100)/64);
}
for (int x=0;x<72;x++)
{
dest[y*256+x]=color;
}
}
  }

  private int interpolateColor(int col1, int col2, int percentage)
  {
  int r=(col1>>16)&0xff;
  int g=(col1>>8)&0xff;
  int b=col1&0xff;
  r+=((((col2>>16)&0xff)-r)*percentage)/100;
  g+=((((col2>>8)&0xff)-g)*percentage)/100;
  b+=(((col2&0xff)-b)*percentage)/100;
  return (r<<16)|(g<<8)|b;
  }

  public boolean containsAlpha()
  {
    return false;
  }
}

AGP

Thank you very much, HRolf, I'll apply it and then post a comment. And great-looking game you made, pal.

AGP

#14
OK, mostly I used the layout of Hrolf's code (as opposed to actually painting the textures with a given color). But now I have a question: do I have to have an instance of my TextureTransition effect per side of the SkyBox? Because I'm thinking I'm going to have to blend each image's pixel with its nighttime equivalent, so it would make sense to have an instance per side, right? Is that redundant (is there another way to to it?) or is it just right?