For a posterization algorithmn I'm going to need to average the color values (QRgb) present in my std::vector.
How would you suggest to do it? Sum the 3 components separately then average them? Otherwise?
Since QRgb is just a 32-bit unsigned int in ARGB format it doesn't suffice for adding colors, which will most likely result in overflow. But also QColor doesn't suffice as it uses fixed-point 16-bit integers for the color components and therefore also cannot cope with colors out of the valid [0,1] range. So you cannot use QRgb or QColor for this as they clamp each partial sum to the valid range. Neither can you predivide the colors before adding them because of their limited precision.
So your best bet would really just be to sum up the individual components using floating point numbers and then divide them by the vector size:
std::vector<QRgb> rgbValues;
float r = 0.0f, g = 0.0f, b = 0.0f, a = 0.0f;
for(std::vector<QRgb>::const_iterator iter=rgbValues.begin();
iter!=rgbValues.end(); ++iter)
{
QColor color(*iter);
r += color.redF();
g += color.greenF();
b += color.blueF();
a += color.alphaF();
}
float scale = 1.0f / float(rgbValues.size());
QRgb = QColor::fromRgbF(r*scale, g*scale, b*scale, a*scale).rgba();
Related
So, I have a light direction in World Space, and I calculate my normals per-vertex... I am however a little confused about my normal map implementation. Right now I'm doing this.
// Normal Map
const float3 normalmap = (2.0f*gTextures1024.Sample(gLinearSam, float3(_in.Tex, gNormalMapIndex)).rgb) - 1.0f;
const float3 NormalW = _in.Norm;
const float3 TangentW = normalize(_in.TangentW.xyz - dot(_in.TangentW.xyz, _in.Norm)* _in.Norm);
const float3 BitangentW = cross(NormalW, TangentW) * _in.TangentW.w;
const float3x3 TBN = float3x3(TangentW, BitangentW, NormalW);
float3 normal = normalize(mul(TBN, normalmap));
// Lighting Calculations
//float4 normal = normalize(float4(_in.Norm, 0.0f));
float3 hvector = normalize(mul(-gDirLight.Direction.xyz, TBN) + gEyePos).xyz;
//hvector = mul(hvector.xyz, TBN);
float4 ambient = gDirLight.Ambient * gMaterial.Ambient;
float4 diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
float4 specular = float4(0.0f, 0.0f, 0.0f, 0.0f);
float4 texColor = float4(1.0f, 1.0f, 1.0f, 1.0f);
[branch]
if(gUseTextures)
texColor = gTextures1024.Sample(gLinearSam, float3(_in.Tex, gDiffuseMapIndex));
// diffuse factor
float diffuseFactor = saturate(dot(normal, -gDirLight.Direction.xyz));
[branch]
if(diffuseFactor > 0.0f)
{
diffuse = diffuseFactor * gDirLight.Diffuse * gMaterial.Diffuse;
// Specular facttor & color
float HdotN = saturate(dot(hvector, normal));
specular = gDirLight.Specular * pow(HdotN, gMaterial.Specular.w);
}
// Modulate with late add
return (texColor * (ambient + diffuse)) + specular;
Am I doing something wrong here? According to me I am implementing the normal maps calculation in world space, and everything should be working just fine... Am I missing something here?
TBN is a matrix that transforms vectors from world space to tangent space. Therefore, you should do lighting calculations in tangent space.
The normal that you acquire from the normal map is already in tangent space (assumably). So you need to transform light direction and eye position to tangent space and continue the calculation as usual.
Nico, you were right. But I had MANY MANY more issues that were creeping up on me.
Issue #1: I wasn't calculating my normals properly. I was using the per vertex average but wasn't even aware that there was such a technique as weighted average. This was a 2000% improvement on all my lighting.
Issue #2: Tangent and Bitangent calculation were not being done correctly either. I might still improve on that area to see if I can also do a weighted average of them.
Issue #3: I wasn't doing my lighting calculations correctly and after being on Wikipedia for about 2 days, I finally did it right, and actually understand it now with complete clarity.
Issue #4: I just wanted to hurry up and do it without understanding 100% what I was doing(never making that mistake AGAIN).
I really got stuck with drawing "roads" on Pixmap in Qt.
I have all coordinates in fractional value which are very close to each other (I've got them from converting longitude/latitude to X/Y coordinates using Mercator's formulas). Qt drawLine function has only integer parameters to draw on a pixmap (cause nobody will draw 2.5 pixels, for example). Moreover, the coordinate starts with top left corner so I need to change it, like this:
Xold = x
Ynew = Ymax - Y
Now I have ordinary X/Y coordinate system, with Y-axis going to top and X-axis going to left.
Here's my code, how I trying to draw lines:
double minlat = 637800*log(tan(3.14/4+3.14*bounds[1]/360.0))/log(2.71),maxlat=637800*log(tan(3.14/4+3.14*bounds[2]/360.0))/log(2.71);
std::vector<double> x;
std::vector<double> y;
QSize size = ui->label_2->size();
size=ui->label_2->size();
QImage pic(size.width(),size.height(),QImage::Format_ARGB32_Premultiplied);
pic.fill(Qt::transparent);
QPainter painter(&pic);
for (unsigned int i=0; i < wayVector.size(); i++){
for (unsigned int j=0; j<wayVector[i].refs.size(); j++){
x.push_back(637800*3.14*nodeHash[wayVector[i].refs[j]].lon/180.0);
y.push_back(637800*log(tan(3.14/4+3.14*nodeHash[wayVector[i].refs[j]].lat/360.0))/log(2.71));
}
for (unsigned int j=0; j<wayVector[i].refs.size()-1;j++){
painter.setPen(Qt::green);
double x1 = x[j]/(size.width()/(maxlon-minlon));
double y1 = maxlat*size.height()/(maxlat-minlat)-y[j]*size.height()/(maxlat-minlat);
double x2 = x[j+1]/(size.width()/(maxlon-minlon));
double y2 = maxlat*size.height()/(maxlat-minlat)-y[j+1]*size.height()/(maxlat-minlat);
painter.drawLine(x1,y1,x2,y2);
}
x.clear();
y.clear();
}
But as soon as I put x1,y1,x2,y2 to drawLine function they converts to integer and everything goes wrong, because all X/Y-coordinates become the same (because of they are very close).
I really don't know how I could draw this lines on a pixmap.
Any ideas?
There are 5 different drawLine() functions. Use void QPainter::drawLine(const QPointF& p1, const QPointF& p2) or void QPainter::drawLine(const QLineF& line) instead. Those types ending with F use doubles.
Is there a single instruction to calculate the sum of all components of a float4, e.g., in OpenCL?
float4 v;
float desiredResult = v.x + v.y + v.z + v.w;
float4 v;
float desiredResult = dot(v, (float4)(1.0f, 1.0f, 1.0f, 1.0f));
It's a little more work, because you're multiplying each component by one before adding them, but some GPUs have a dot product instruction built in. So might be faster; might be slower. It depends on your hardware.
Time for a little bit of math for the end of the day..
I need to project 4 points of the window size:
<0,0> <1024,768>
Into a world space coordinates so it will form a quadrilateral shape that will later be used for terrain culling - without GluUnproject
For test only, I use mouse coordinates - and try to project them onto the world coords
RESOLVED
Here's how to do it exactly, step by step.
Obtain your mouse coordinates within the client area
Get your Projection matrix and View matrix if no Model matrix required.
Multiply Projection * View
Inverse the results of multiplication
Construct a vector4 consisting of
x = mouseposition.x within a range of window x
transform to values between -1 and 1
y = mouseposition.y within a range of window y
transform to values between -1 and 1
remember to invert mouseposition.y if needed
z = the depth value ( this can be obtained with glReadPixel)
you can manually go from -1 to 1 ( zNear, zFar )
w = 1.0
Multiply the vector by inversed matrix created before
Divide result vector by it's w component after matrix multiplication ( perspective division )
POINT mousePos;
GetCursorPos(&mousePos);
ScreenToClient( this->GetWindowHWND(), &mousePos );
CMatrix4x4 matProjection = m_pCamera->getViewMatrix() * m_pCamera->getProjectionMatrix() ;
CMatrix4x4 matInverse = matProjection.inverse();
float in[4];
float winZ = 1.0;
in[0]=(2.0f*((float)(mousePos.x-0)/(this->GetResolution().x-0)))-1.0f,
in[1]=1.0f-(2.0f*((float)(mousePos.y-0)/(this->GetResolution().y-0)));
in[2]=2.0* winZ -1.0;
in[3]=1.0;
CVector4 vIn = CVector4(in[0],in[1],in[2],in[3]);
pos = vIn * matInverse;
pos.w = 1.0 / pos.w;
pos.x *= pos.w;
pos.y *= pos.w;
pos.z *= pos.w;
sprintf(strTitle,"%f %f %f / %f,%f,%f ",m_pCamera->m_vPosition.x,m_pCamera->m_vPosition.y,m_pCamera->m_vPosition.z,pos.x,pos.y,pos.z);
SetWindowText(this->GetWindowHWND(),strTitle);
I had to make some adjustments to the answers provided here. But here's the code I ended up with (Note I'm using GLM, that could affect multiplication order). nearResult is the projected point on the near plane and farResult is the projected point on the far plane. I want to perform a ray cast to see what my mouse is hovering over so I convert them to a direction vector which will then originate from my camera's position.
vec3 getRayFromScreenSpace(const vec2 & pos)
{
mat4 invMat= inverse(m_glData.getPerspective()*m_glData.getView());
vec4 near = vec4((pos.x - Constants::m_halfScreenWidth) / Constants::m_halfScreenWidth, -1*(pos.y - Constants::m_halfScreenHeight) / Constants::m_halfScreenHeight, -1, 1.0);
vec4 far = vec4((pos.x - Constants::m_halfScreenWidth) / Constants::m_halfScreenWidth, -1*(pos.y - Constants::m_halfScreenHeight) / Constants::m_halfScreenHeight, 1, 1.0);
vec4 nearResult = invMat*near;
vec4 farResult = invMat*far;
nearResult /= nearResult.w;
farResult /= farResult.w;
vec3 dir = vec3(farResult - nearResult );
return normalize(dir);
}
Multiply all your matrices. Then invert the result. Point after projection are always in the -1,1. So the four corner screen points are -1,-1; -1,1; 1,-1;1,1. But you still need to choose th z value. If you are in OpenGL, z is between -1 and 1. For directx, the range is 0 to 1. Finally take your points and transform them with the matrix
If you have access to the glu libraries, use gluUnProject(winX, winY, winZ, model, projection, viewport, &objX, &objY, &objZ);
winX and winY will be the corners of your screen in pixels. winZ is a number in [0,1] which will specify where between zNear and zFar (clipping planes) the points should fall. objX-Z will hold the results. The middle variables are the relevant matrices. They can be queried if needed.
I'm developing a simple 2D board game using hexagonal tile maps, I've read several articles (including the gamedev one's, which are linked every time there's a question on hexagonal tiles) on how to draw hexes on the screen and how to manage the movement (though much of it I had already done before). My main problem is finding the adjacent tiles based on a given radius.
This is how my map system works:
(0,0) (0,1) (0,2) (0,3) (0,4)
(1,0) (1,1) (1,2) (1,3) (1,4)
(2,0) (2,1) (2,2) (2,3) (2,4)
(3,0) (3,1) (3,2) (3,3) (3,4)
etc...
What I'm struggling with is the fact that I cant just 'select' the adjacent tiles by using for(x-range;x+range;x++); for(y-range;y+range;y++); because it selects unwanted tiles (in the example I gave, selecting the (1,1) tile and giving a range of 1 would also give me the (3,0) tile (the ones I actually need being (0,1)(0,2)(1,0)(1,2)(2,1)(2,2) ), which is kinda adjacent to the tile (because of the way the array is structured) but it's not really what I want to select. I could just brute force it, but that wouldn't be beautiful and would probably not cover every aspect of 'selecting radius thing'.
Can someone point me in the right direction here?
What is a hexagonal grid?
What you can see above are the two grids. It's all in the way you number your tiles and the way you understand what a hexagonal grid is. The way I see it, a hexagonal grid is nothing more than a deformed orthogonal one.
The two hex tiles I've circled in purple are theoretically still adjacent to 0,0. However, due to the deformation we've gone through to obtain the hex-tile grid from the orthogonal one, the two are no longer visually adjacent.
Deformation
What we need to understand is the deformation happened in a certain direction, along a [(-1,1) (1,-1)] imaginary line in my example. To be more precise, it is as if the grid has been elongated along that line, and squashed along a line perpendicular to that. So naturally, the two tiles on that line got spread out and are no longer visually adjacent. Conversely, the tiles (1, 1) and (-1, -1) which were diagonal to (0, 0) are now unusually close to (0, 0), so close in fact that they are now visually adjacent to (0, 0). Mathematically however, they are still diagonals and it helps to treat them that way in your code.
Selection
The image I show illustrates a radius of 1. For a radius of two, you'll notice (2, -2) and (-2, 2) are the tiles that should not be included in the selection. And so on. So, for any selection of radius r, the points (r, -r) and (-r, r) should not be selected. Other than that, your selection algorithm should be the same as a square-tiled grid.
Just make sure you have your axis set up properly on the hexagonal grid, and that you are numbering your tiles accordingly.
Implementation
Let's expand on this for a bit. We now know that movement along any direction in the grid costs us 1. And movement along the stretched direction costs us 2. See (0, 0) to (-1, 1) for example.
Knowing this, we can compute the shortest distance between any two tiles on such a grid, by decomposing the distance into two components: a diagonal movement and a straight movement along one of the axis.
For example, for the distance between (1, 1) and (-2, 5) on a normal grid we have:
Normal distance = (1, 1) - (-2, 5) = (3, -4)
That would be the distance vector between the two tiles were they on a square grid. However we need to compensate for the grid deformation so we decompose like this:
(3, -4) = (3, -3) + (0, -1)
As you can see, we've decomposed the vector into one diagonal one (3, -3) and one straight along an axis (0, -1).
We now check to see if the diagonal one is along the deformation axis which is any point (n, -n) where n is an integer that can be either positive or negative.
(3, -3) does indeed satisfy that condition, so this diagonal vector is along the deformation. This means that the length (or cost) of this vector instead of being 3, it will be double, that is 6.
So to recap. The distance between (1, 1) and (-2, 5) is the length of (3, -3) plus the length of (0, -1). That is distance = 3 * 2 + 1 = 7.
Implementation in C++
Below is the implementation in C++ of the algorithm I have explained above:
int ComputeDistanceHexGrid(const Point & A, const Point & B)
{
// compute distance as we would on a normal grid
Point distance;
distance.x = A.x - B.x;
distance.y = A.y - B.y;
// compensate for grid deformation
// grid is stretched along (-n, n) line so points along that line have
// a distance of 2 between them instead of 1
// to calculate the shortest path, we decompose it into one diagonal movement(shortcut)
// and one straight movement along an axis
Point diagonalMovement;
int lesserCoord = abs(distance.x) < abs(distance.y) ? abs(distance.x) : abs(distance.y);
diagonalMovement.x = (distance.x < 0) ? -lesserCoord : lesserCoord; // keep the sign
diagonalMovement.y = (distance.y < 0) ? -lesserCoord : lesserCoord; // keep the sign
Point straightMovement;
// one of x or y should always be 0 because we are calculating a straight
// line along one of the axis
straightMovement.x = distance.x - diagonalMovement.x;
straightMovement.y = distance.y - diagonalMovement.y;
// calculate distance
size_t straightDistance = abs(straightMovement.x) + abs(straightMovement.y);
size_t diagonalDistance = abs(diagonalMovement.x);
// if we are traveling diagonally along the stretch deformation we double
// the diagonal distance
if ( (diagonalMovement.x < 0 && diagonalMovement.y > 0) ||
(diagonalMovement.x > 0 && diagonalMovement.y < 0) )
{
diagonalDistance *= 2;
}
return straightDistance + diagonalDistance;
}
Now, given the above implemented ComputeDistanceHexGrid function, you can now have a naive, unoptimized implementation of a selection algorithm that will ignore any tiles further than the specified selection range:
int _tmain(int argc, _TCHAR* argv[])
{
// your radius selection now becomes your usual orthogonal algorithm
// except you eliminate hex tiles too far away from your selection center
// for(x-range;x+range;x++); for(y-range;y+range;y++);
Point selectionCenter = {1, 1};
int range = 1;
for ( int x = selectionCenter.x - range;
x <= selectionCenter.x + range;
++x )
{
for ( int y = selectionCenter.y - range;
y <= selectionCenter.y + range;
++y )
{
Point p = {x, y};
if ( ComputeDistanceHexGrid(selectionCenter, p) <= range )
cout << "(" << x << ", " << y << ")" << endl;
else
{
// do nothing, skip this tile since it is out of selection range
}
}
}
return 0;
}
For a selection point (1, 1) and a range of 1, the above code will display the expected result:
(0, 0)
(0, 1)
(1, 0)
(1, 1)
(1, 2)
(2, 1)
(2, 2)
Possible optimization
For optimizing this, you can include the logic of knowing how far a tile is from the selection point (logic found in ComputeDistanceHexGrid) directly into your selection loop, so you can iterate the grid in a way that avoids out of range tiles altogether.
Simplest method i can think of...
minX = x-range; maxX = x+range
select (minX,y) to (maxX, y), excluding (x,y) if that's what you want to do
for each i from 1 to range:
if y+i is odd then maxX -= 1, otherwise minX += 1
select (minX, y+i) to (maxX, y+i)
select (minX, y-i) to (maxX, y-i)
It may be a little off; i just worked it through in my head. But at the very least, it's an idea of what you need to do.
In C'ish:
void select(int x, int y) {
/* todo: implement this */
/* should ignore coordinates that are out of bounds */
}
void selectRange(int x, int y, int range) {
int minX = x - range, maxX = x + range;
for (int i = minX; i <= maxX; ++i) {
if (i != x) select(i, y);
}
for (int yOff = 1; yOff <= range; ++yOff) {
if ((y+yOff) % 2 == 1) --maxX; else ++minX;
for (int i=minX; i<=maxX; ++i) {
select(i, y+yOff);
select(i, y-yOff);
}
}
}