3D Object selection in opengl - java

I am currently making a 3d chess game in opengl. I still struggle with the selection of the different figures. I followed the tutorials by thinmatrix and came this far: https://imgur.com/gallery/oLv5ReI.
Now I want the user to be able to select the figures by clicking on them. I have the camera position, the ray in which direction the mouse is pointing and the position of the figures. How can I detect if the ray hits the figure (probably using a rectangle hitbox) when it starts at the position of the camera?
My code so far:
public void update(Vector3f mouseRay, Camera camera, Figure figure){
Vector3f start = camera.getPosition();
Vector3f figurePos = figure.getPosition();
if(intersect()){
selectFigure();
}
}
EDIT:
I tried this:
Ray-Sphere intersection
but it somehow didn't work. A sphere intersection also seemed very inefficient in respect of a ray box intersection.

You'll have to follow following steps (I'm assuming you are aware of rendering pipeline and aware of OpenGL/WebGL)
Get the list of all the objects you have.
Assign every object a unique color. Following would be an easy way to assign the unique color based on index of the object in the list.
int i = // Index of the object
// We've added 1 to the index because 0 index is translated to black color
// And our background is also rendered as black so we skip will that color.
int r = (i + 1 & 0x000000FF) >> 0;
int g = (i + 1 & 0x0000FF00) >> 8;
int b = (i + 1 & 0x00FF0000) >> 16;
glm::vec4 unique_color = glm::vec4(r / 255.0f, g / 255.0f, b / 255.0f, 1.0);
Create a frame-buffer and render all the objects with their uniquely assigned solid colors.
When the rendering is complete, you now read the click position pixel color from the rendered frame buffer texture.
Decode the color into index of object back like given below. (This is exactly revers of what we've done in step 2)
int triangle_index =
color.r +
color.g * 256 +
color.b * 256 * 256;
With this index you have the selected object from the initial list of all objects.
You can read more about this technique here, http://www.opengl-tutorial.org/miscellaneous/clicking-on-objects/picking-with-an-opengl-hack/

Related

Weird interpolation between colors in hsv?

I want to achieve interpolation between red and blue. something like this
but in a single line.
My java code:
private PixelData InterpolateColour(float totalLength, float curLength){
float startColourV[] = new float[3];
Color.RGBtoHSB(m_start.getColour().getR() & 0xFF, m_start.getColour().getG() & 0xFF, m_start.getColour().getB() & 0xFF, startColourV);
float endColourV[] = new float[3];
Color.RGBtoHSB(m_end.getColour().getR() & 0xFF, m_end.getColour().getG() & 0xFF, m_end.getColour().getB() & 0xFF, endColourV);
float endPercent = curLength / totalLength;
float startPercent = 1 - curLength / totalLength;
float h = endColourV[0] * endPercent + startColourV[0] * startPercent;
float s = endColourV[1] * endPercent + startColourV[1] * startPercent;
float b = endColourV[2] * endPercent + startColourV[2] * startPercent;
int colourRGB = Color.HSBtoRGB(h, s, b);
byte[] ByteArray = ByteBuffer.allocate(4).putInt(colourRGB).array();
return new PixelData(ByteArray[0], ByteArray[3], ByteArray[2], ByteArray[1]);
}
and the result i am getting is this
.
I don't understand, from where all that green is coming from. Can somebody please help me ?
why not use just RGB with simple linear interpolation for this:
color(t)=(color0*t)+(color1*(1.0-t))
where t=<0.0,1.0> is the parameter. So just loop it in the full range with as many steps as you need.
Integer C++/VCL example (sorry not a JAVA coder):
// borland GDI clear screen
Canvas->Brush->Color=clBlack;
Canvas->FillRect(ClientRect);
// easy access to RGB channels
union _color
{
DWORD dd;
BYTE db[4];
} c0,c1,c;
// 0x00BBGGRR
c0.dd=0x000000FF; // Red
c1.dd=0x00FF0000; // Blue
int x,y,t0,t1;
for (x=0,y=ClientHeight/2;x<ClientWidth;x++)
{
t0=x;
t1=ClientWidth-1-x;
c.db[0]=((DWORD(c0.db[0])*t0)+(DWORD(c1.db[0])*t1))/(ClientWidth-1);
c.db[1]=((DWORD(c0.db[1])*t0)+(DWORD(c1.db[1])*t1))/(ClientWidth-1);
c.db[2]=((DWORD(c0.db[2])*t0)+(DWORD(c1.db[2])*t1))/(ClientWidth-1);
c.db[3]=((DWORD(c0.db[3])*t0)+(DWORD(c1.db[3])*t1))/(ClientWidth-1);
Canvas->Pixels[x][y]=c.dd;
}
where ClientWidth,ClientHeight is my app form resolution, Canvas is access to the GDI interface of the form and Canvas->Pixels[x][y] is single pixel access (slow but for this example it is enough). The only important stuff is the for loop. Here resulting image:
Color interpolation is actually a fairly complex topic due to the way human vision works.
Physical intensity and wavelengths don't map directly to perceived luminance and hues. After all human eyes are not photon spectrometers, they just measure the intensity + three primaries, each with different sensitivity.
To have a metric, linear space that represents human color perception instead of physical attributes we have the CIELab. Since it's a linear metric doing interpolation between points should generally give you a linear transition between hues and also luminance.
But CIELab may not be sufficient since it only models perceptual sensitivity. If you need to match real lighting you also have to take into account that natural light sources do not illuminate all colors evenly.
If you need to match photorealistic material then additionally correcting for the intensity spectrum of natural light may also be necessary. I.e. something illuminated by a candle will not have intense blue components simply because the candle emits very little blue light that could be reflected.

Get convolution matrix from image samples?

Im trying to decompile the convolution matrix for the filters on the Motorola Gallery App
Im using the following code to read the pixel data:
public static void main(String[] foo) {
new JavaWalkBufferedImageTest1();
}
public void printPixelARGB(int pixel) {
int alpha = (pixel >> 24) & 0xff;
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel) & 0xff;
System.out.println("argb: " + alpha + ", " + red + ", " + green + ", " + blue);
}
private void marchThroughImage(BufferedImage image) {
int w = image.getWidth();
int h = image.getHeight();
System.out.println("width, height: " + w + ", " + h);
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
System.out.println("x,y: " + j + ", " + i);
int pixel = image.getRGB(j, i);
printPixelARGB(pixel);
System.out.println("");
}
}
}
public JavaWalkBufferedImageTest1() {
try {
// get the BufferedImage, using the ImageIO class
BufferedImage image =
ImageIO.read(this.getClass().getResource("WhiteSpot.jpg"));
marchThroughImage(image);
} catch (IOException e) {
System.err.println(e.getMessage());
}
}
It gives the desired output.
But this is not leading me anywhere into finding the matrix.
How do I modify the code so that I can input 2 image files, Original & Filtered. And get the convolution matrix. Or is there an online tool that I can use, where I upload multiple Original & Filtered samples, and get the convolution matrix?
I would approach this problem (will work if only convolution was applied and only once!) like this:
first you need to find matrix size.
So you can loop through all possible matrix sizes or use a big one expecting zero values inside. That can be slow but you can try to estimate matrix size from the bluryness of sharp intensity edges (to how many pixels is the color bleeded).
for tested (big) matrix size try to find zero values
So for each tested matrix value form 2 arrays. One with few samples of pixels from convoluted image and second with pixels (shifted by tested matrix position) from original image. Now compute correlation coefficient between the two and if no significant correlation present you can assume the value in matrix is zero.
solve the remaining nonzero values in matrix
You can do this algebraically (form as many equation as many nonzero values you have (do not forget to choose pixels with different color). Or you can do search to minimize error/distance of convoluted output by your matrix and the real convoluted output. You can use something like mine approx class in C++ for this but if Your matrix is big then this will take a lot of time.
[Notes]
If more then just single convolution is applied to image then this will most likely not work.
Convolution matrices are mostly square and symmetric around mid value so you can compute the quarter of values and mirror the rest ... speeding up the computation.
Also see Dealing with filters and colour's which is similar question.
Bullet #2 can be used to detect the matrix size. As usually the max nonzero values are in the central cross of matrix.
0 0 2 0 0
0 1 2 1 0
2 2 3 2 2
0 1 2 1 0
0 0 2 0 0
Values 2 are the central cross and value 3 is the mid value of convolution matrix. So start computing the #2 correlations from mid point in x and y direction. And when hit zero value you are most likely at the edge of convolution matrix. So you can use that as matrix size (unless the matrix is some weird filter ...).
Also each color channel can have its own convolution matrix so may be you should do this separately per channel (and convolution can be done in any color space not just in RGB).
There might be other approaches for this (my guts tells me this should be solvable by PCA)
If you got black area in the original image then you can use that to find the values of matrix more easily (it will significantly ease up the algebraic approach)

Generate n colors between two colors

I'm trying to write function, which can generate colors between two colors based on a given value. An example would explain it better..
Input ..
X : 1
Y : 0.5
Z : 0
The user gives any set of color:value pairs, then enters a number(say 0.75). I have to then generate color which is a blend of Y and Z in proportion(based on the their values and the input value). I was thinking of the following approach.
Find the colors which surround the value, for 0.75 it will be 0.5 and 1.
Mix those two colors somehow, based on the value and generate new colors.
I'm completely lost, as how to generate colors and are there any libraries for this.
UPDATE:
It is part of a bigger project I'm working on. Lets say we have ..
1 : X
0 : Y
and the user inputs, 0.25
I would like to have something..
(X*0.25 + Y*0.75)
as it's more near to Y, that's why the higher proportion. If the user inputs, 0.5.. the output should be
(X*0.5 + Y*0.5)
and so on. I have no idea how to do this with RGB colors.
P.S: The questions is not specific to language, but I'm doing this in Java.
You have to blend each color channel (red, green and blue) seperately like this:
Color x,y; //set by you
float blending;//set by you
float inverse_blending = 1 - blending;
float red = x.getRed() * blending + y.getRed() * inverse_blending;
float green = x.getGreen() * blending + y.getGreen() * inverse_blending;
float blue = x.getBlue() * blending + y.getBlue() * inverse_blending;
//note that if i pass float values they have to be in the range of 0.0-1.0
//and not in 0-255 like the ones i get returned by the getters.
Color blended = new Color (red / 255, green / 255, blue / 255);
So far for the color example. Generally if you want a linear interpolation between two values you have to do the following:
var firstValue;
var secondValue;
var interpolation;
var interpolated = firstValue * interpolation +
secondValue * (1 - interpolation);
But since you have Color-Objects in your case, you cannot interpolate the whole object in one step, you have to interpolate each relevant value on its own. Eventually you have to interpolate the alpha-channel as well, don´t know that, since you didn´t mention it, but for completeness i include it in this answer.
A color is a point in a three-dimensional space. The exact coordinates used depend on what's called a "color space", of which there are several: RGB, HSV, and so on. So to compute a color in between two given colors, get those two colors in the same color space, and compute a third point between those two along the line in 3d-space between them.
The simplest way to do this would be simply to do a linear interpolation for each of the three values of the colorspace (R, G, and B, for example). But there's a further complication that the coordinate values are often not linear, so you have to linearize them first (for example, TV colors are exponential with a lambda of about 2.2). Depending on your application, incorrectly assuming linearity might work OK anyway, especially if the starting colors are already close.
(As mentioned by luk2302, add a fourth coordinate for alpha if necessary).
You could use Java.awt.color by doing somting like this:
public Color mixColors(Color color1, Color color2, double percent){
double inverse_percent = 1.0 - percent;
int redPart = (int) (color1.getRed()*percent + color2.getRed()*inverse_percent);
int greenPart = (int) (color1.getGreen()*percent + color2.getGreen()*inverse_percent);
int bluePart = (int) (color1.getBlue()*percent + color2.getBlue()*inverse_percent);
return new Color(redPart, greenPart, bluePart);
}

changing rgb color values to represent a value

I am trying to make a color change on a canvas in java to respresent how strong or weak the values respresented by color are relative to each other.
The rgb colors have to be the same color just different shades, like white to grey to black and every shade of grey in between. How can I change the rgb values considering that the values I am representing vary a lot, from -9999999 to positive 9999999.
I think you should take a look at HSL/HSV instead of RGB.
While RGB is elementary in nature in that it expresses colors in terms of the primaries, it does not allow you to make "understandable" changes to the R, G or B values to arrive at "similar" colors. With a HSL/HSV model, you will be able to make changes to Brightness/Lightness/Value (L/V) to arrive at colors with varying amounts of gray, or make changes to Hue (H) to obtain similar colors across the spectrum. You can start at full brightness (White) and create darker tones of gray by decreasing the value of L/V and eventually reach the color of no brightness (Black).
A very mild introduction to color theory, for developers is available here.
As to your question, you should express your colors in terms of HSL, with increasing values of Saturation to have a range of colors starting from white to black. Of course, if you want gray tones in between white and black without any other color, you should keep the hue to a minimum.
A short example on how to get a range of colors follows. For brevity, I've populated the colors into an array, but that is not required since you might want to use the color rightaway (besides considering memory requirements).
private Color[] produceColorRange(int steps)
{
float value = 1.0f; //Starting with full brightness
Color[] colors = new Color[steps];
for(int ctr = 0; ctr < steps; ctr++)
{
value = value - (1.0f/steps); //tend to darkness
int rgb = Color.HSBtoRGB(0.7f, 0.0f, value); //create a darker color
//Hue is Blue, not noticeable
//because Saturation is 0
Color color = new Color(rgb);
colors[ctr] = color;
}
return colors;
}
If you use the above method and paint a JFrame, you will be able to get a result similar to the one below (except that I've modified the hue and saturation to get my color range).
Note that if you want a simpler way of getting a color range, initialize a Color object with Color.WHITE and invoke color.darker(). Of course, you will not be able to control the increment.
Yes, scale your values to fit your domain. That depends on how your RGB values are stored. Usually, 8 bits are used for each. Since grey has R = G = B, you want to scale values in range (-9999999,9999999) to (0, 255).
Consider x in the first interval. Since the first range covers also negative numbers, first, do a shift.
x = x + 9999999
Now x is in the interval (0, 19999998). And the next step is to scale it down to (0, 255). Since the colour values grow linearly in that interval, all you have to do is this:
x = x * 255 / 19999998
Now x is in the interval (0, 255) just like you want.
Generally, if your inital values are in an interval (a, b) and want to transform it into (0, c), apply this formula: (Note that a can be negative)
x = (x - a) * c / (b - a)
So if you R, G, B values are 16 bits long, c will be 2**16 = 65536 and the formula:
x = (x + 9999999) * 65536 / 19999998
Hope that helps.
I'm not completely sure I understand your question, but, if I do:
Why not just scale the RGB values to the values in your range (from -9999999 to positive 9999999)? Moreover, set R, G, and B all to the same value so that you're using shades of gray to represent the value.
Like this:
private final int MIN = -9999999;
private final int MAX = 9999999;
public Color getScaledColor(int val) {
int gray = (int) Math.round((double) (val - MIN) / (double) (MAX - MIN)
* 255.0);
Color color = new Color(gray, gray, gray);
return color;
}
Note that this solution will not give unique colors for all the values in the range you specified. But also keep in mind that the human eye can only distinguish between so many shades (and 2 * 9999999 + 1 is probably more than the number of shades than it can distinguish between).
The HSL Color class implements the formulas provided in the Wikipedia link on HSL/HSV provide above.

Customizable player avatar in a 2D Game

How can I have that functionality in my game through which the players can change their hairstyle, look, style of clothes, etc., and so whenever they wear a different item of clothing their avatar is updated with it.
Should I:
Have my designer create all possible combinations of armor, hairstyles, and faces as sprites (this could be a lot of work).
When the player chooses what they should look like during their introduction to the game, my code would automatically create this sprite, and all possible combinations of headgear/armor with that sprite. Then each time they select some different armor, the sprite for that armor/look combination is loaded.
Is it possible to have a character's sprite divided into components, like face, shirt, jeans, shoes, and have the pixel dimensions of each of these. Then whenever the player changes his helmet, for example, we use the pixel dimensions to put the helmet image in place of where its face image would normally be. (I'm using Java to build this game)
Is this not possible in 2D and I should use 3D for this?
Any other method?
Please advise.
One major factor to consider is animation. If a character has armour with shoulder pads, those shoulderpads may need to move with his torso. Likewise, if he's wearing boots, those have to follow the same cycles as hid bare feet would.
Essentially what you need for your designers is a Sprite Sheet that lets your artists see all possible frames of animation for your base character. You then have them create custom hairstyles, boots, armour, etc. based on those sheets. Yes, its a lot of work, but in most cases, the elements will require a minimal amount of redrawing; boots are about the only thing I could see really taking a lot of work to re-create since they change over multiple frames of animation. Be rutheless with your sprites, try to cut down the required number as much as possible.
After you've amassed a library of elements you can start cheating. Recycle the same hair style and adjust its colour either in Photoshop or directly in the game with sliders in your character creator.
The last step, to ensure good performance in-game, would be to flatten all the different elements' sprite sheets into a single sprite sheet that is then split up and stored in sprite buffers.
3D will not be necessary for this, but the painter algorithm that is common in the 3D world might IMHO save you some work:
The painter algorithm works by drawing the most distant objects first, then overdrawing with objects closer to the camera. In your case, it would boild down to generating the buffer for your sprite, drawing it onto the buffer, finding the next dependant sprite-part (i.e. armour or whatnot), drawing that, finding the next dependant sprite-part (i.e. a special sign that's on the armour), and so on. When there are no more dependant parts, you paint the full generated sprite on to the display the user sees.
The combinated parts should have an alpha channel (RGBA instead of RGB) so that you will only combine parts that have an alpha value set to a value of your choice. If you cannot do that for whatever reason, just stick with one RGB combination that you will treat as transparent.
Using 3D might make combining the parts easier for you, and you'd not even have to use an offscreen buffer or write the pixel combinating code. The flip-side is that you need to learn a little 3D if you don't know it already. :-)
Edit to answer comment:
The combination part would work somewhat like this (in C++, Java will be pretty similar - please note that I did not run the code below through a compiler):
//
// #param dependant_textures is a vector of textures where
// texture n+1 depends on texture n.
// #param combimed_tex is the output of all textures combined
void Sprite::combineTextures (vector<Texture> const& dependant_textures,
Texture& combined_tex) {
vector< Texture >::iterator iter = dependant_textures.begin();
combined_tex = *iter;
if (dependant_textures.size() > 1)
for (iter++; iter != dependant_textures.end(); iter++) {
Texture& current_tex = *iter;
// Go through each pixel, painting:
for (unsigned char pixel_index = 0;
pixel_index < current_tex.numPixels(); pixel_index++) {
// Assuming that Texture had a method to export the raw pixel data
// as an array of chars - to illustrate, check Alpha value:
int const BYTESPERPIXEL = 4; // RGBA
if (!current_tex.getRawData()[pixel_index * BYTESPERPIXEL + 3])
for (int copied_bytes = 0; copied_bytes < 3; copied_bytes++)
{
int index = pixel_index * BYTESPERPIXEL + copied_bytes;
combined_tex.getRawData()[index] =
current_tex.getRawData()[index];
}
}
}
}
To answer your question for a 3D solution, you would simply draw rectangles with their respective textures (that would have an alpha channel) over each other. You would set the system up to display in an orthogonal mode (for OpenGL: gluOrtho2D()).
I'd go with the procedural generation solution (#2). As long as there isn't a limiting amount of sprites to be generated, such that the generation takes too long. Maybe do the generation when each item is acquired, to lower the load.
Since I was asked in comments to supply a 3D way aswell, here is some, that is an excerpt of some code I wrote quite some time ago. It's OpenGL and C++.
Each sprite would be asked to draw itself. Using the Adapter pattern, I would combine sprites - i.e. there would be sprites that would hold two or more sprites that had a (0,0) relative position and one sprite with a real position having all those "sub-"sprites.
void Sprite::display (void) const
{
glBindTexture(GL_TEXTURE_2D, tex_id_);
Display::drawTranspRect(model_->getPosition().x + draw_dimensions_[0] / 2.0f,
model_->getPosition().y + draw_dimensions_[1] / 2.0f,
draw_dimensions_[0] / 2.0f, draw_dimensions_[1] / 2.0f);
}
void Display::drawTranspRect (float x, float y, float x_len, float y_len)
{
glPushMatrix();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1.0, 1.0, 1.0, 1.0);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(x - x_len, y - y_len, Z);
glTexCoord2f(1.0f, 0.0f); glVertex3f(x + x_len, y - y_len, Z);
glTexCoord2f(1.0f, 1.0f); glVertex3f(x + x_len, y + y_len, Z);
glTexCoord2f(0.0f, 1.0f); glVertex3f(x - x_len, y + y_len, Z);
glEnd();
glDisable(GL_BLEND);
glPopMatrix();
}
The tex_id_ is an integral value that identifies which texture is used to OpenGL. The relevant parts of the texture manager are these. The texture manager actually emulates an alpha channel by checking to see if the color read is pure white (RGB of (ff,ff,ff)) - the loadFile code operates on 24 bits per pixel BMP files:
TextureManager::texture_id
TextureManager::createNewTexture (Texture const& tex) {
texture_id id;
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 4, tex.width_, tex.height_, 0,
GL_BGRA_EXT, GL_UNSIGNED_BYTE, tex.texture_);
return id;
}
void TextureManager::loadImage (FILE* f, Texture& dest) const {
fseek(f, 18, SEEK_SET);
signed int compression_method;
unsigned int const HEADER_SIZE = 54;
fread(&dest.width_, sizeof(unsigned int), 1, f);
fread(&dest.height_, sizeof(unsigned int), 1, f);
fseek(f, 28, SEEK_SET);
fread(&dest.bpp_, sizeof (unsigned short), 1, f);
fseek(f, 30, SEEK_SET);
fread(&compression_method, sizeof(unsigned int), 1, f);
// We add 4 channels, because we will manually set an alpha channel
// for the color white.
dest.size_ = dest.width_ * dest.height_ * dest.bpp_/8 * 4;
dest.texture_ = new unsigned char[dest.size_];
unsigned char* buffer = new unsigned char[3 * dest.size_ / 4];
// Slurp in whole file and replace all white colors with green
// values and an alpha value of 0:
fseek(f, HEADER_SIZE, SEEK_SET);
fread (buffer, sizeof(unsigned char), 3 * dest.size_ / 4, f);
for (unsigned int count = 0; count < dest.width_ * dest.height_; count++) {
dest.texture_[0+count*4] = buffer[0+count*3];
dest.texture_[1+count*4] = buffer[1+count*3];
dest.texture_[2+count*4] = buffer[2+count*3];
dest.texture_[3+count*4] = 0xff;
if (dest.texture_[0+count*4] == 0xff &&
dest.texture_[1+count*4] == 0xff &&
dest.texture_[2+count*4] == 0xff) {
dest.texture_[0+count*4] = 0x00;
dest.texture_[1+count*4] = 0xff;
dest.texture_[2+count*4] = 0x00;
dest.texture_[3+count*4] = 0x00;
dest.uses_alpha_ = true;
}
}
delete[] buffer;
}
This was actually a small Jump'nRun that I developed occasionally in my spare time. It used gluOrtho2D() mode aswell, btw. If you leave means to contact you, I will send you the source if you want.
Older 2d games such as Diablo and Ultima Online use a sprite compositing technique to do this. You could search for art from those kind of older 2d isometric games to see how they did it.

Categories

Resources