How to fit/clip an axis aligned bounding box around a portion of a triangle - geometry

I have looked and looked and cannot find any resources on. I want to clip an axis aligned bounding box against a triangle in a way that creates a new tight fitting axis aligned bounding box around or in the triangle (I have seen the reverse a lot, a triangle clipped against an axis alinged bounding, but never seen the reverse case). I tried computing the clipped tiangle then building a bounding box from it. But it is grossly inefficent and I don't think my code is correct. Does anyone know how to clip a bounding box against a triangle efficently?
Here is pictures describing what I currently do
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
typedef float f32;
typedef double f64;
struct Point
{
union
{
f32 a[3];
struct
{
f32 x;
f32 y;
f32 z;
};
};
};
struct BoundingBox3
{
Point m_vMin = {FLT_MAX,FLT_MAX,FLT_MAX};
Point m_vMax = {-FLT_MAX,-FLT_MAX,-FLT_MAX};
};
inline
s8 Classify( s8 sign, u8 axis, const Point *c_v, const Point *p_v )
{
const f64 d = sign * ( p_v->a[axis] - c_v->a[axis] );
if ( d > EPSILON )
{
return 1;
}
else if ( d < -EPSILON )
{
return -1;
}
return 0;
}
#define POINT_BUFFER_SIZE 9
inline
void Clip3D_plane( Point *pVerts, s8 sign, u8 axis, u8 *pdwNumVerts, const Point *pPointOnPlane )
{
u8 dwNumVerts = ( *pdwNumVerts );
if ( dwNumVerts == 0 )
{
return;
}
else if ( dwNumVerts == 1 )
{
*pdwNumVerts = 0;
return;
}
Point vNewVerts[POINT_BUFFER_SIZE];
u8 k = 0;
bool b = true; // polygon is fully located on clipping plane
Point v1 = pVerts[dwNumVerts - 1];
s8 d1 = Classify( sign, axis, pPointOnPlane, &v1 );
for ( u8 j = 0; j < dwNumVerts; ++j )
{
const Point &v2 = pVerts[j];
s8 d2 = Classify( sign, axis, pPointOnPlane, &v2 );
if ( d2 != 0 )
{
b = false;
if ( ( 0x80 & ( d2 ^ d1 ) ) != 0 ) //if signs differ
{
const f32 fAlpha = ( v2.a[axis] - pPointOnPlane->a[axis] ) / ( v2.a[axis] - v1.a[axis] );
Point_Lerp( &v2, &v1, fAlpha, &vNewVerts[k++] );
}
else if ( d1 == 0 && ( k == 0 || !Point_Equals( &vNewVerts[k - 1], &v1 ) ) )
{
vNewVerts[k++] = v1;
}
if ( d2 > 0 )
{
vNewVerts[k++] = v2;
}
}
else
{
if ( d1 != 0 )
{
vNewVerts[k++] = v2;
}
}
v1 = v2;
d1 = d2;
}
if ( b )
{
return;
}
*pdwNumVerts = k;
for ( u8 j = 0; j < k; ++j )
{
pVerts[j] = vNewVerts[j];
}
}
inline void BoundingBox_Append( BoundingBox3 *pBB, const Point *pvPoint )
{
pBB->m_vMin.x = min( pBB->m_vMin.x, pvPoint->x );
pBB->m_vMin.y = min( pBB->m_vMin.y, pvPoint->y );
pBB->m_vMin.z = min( pBB->m_vMin.z, pvPoint->z );
pBB->m_vMax.x = max( pBB->m_vMax.x, pvPoint->x );
pBB->m_vMax.y = max( pBB->m_vMax.y, pvPoint->y );
pBB->m_vMax.z = max( pBB->m_vMax.z, pvPoint->z );
}
void BoundingBox_ClipAndAppendTri( BoundingBox3 *pBB3, Point *pVerts, u8 *phwNumVerts, const BoundingBox3 *pClipBox )
{
for ( u8 axis = 0; axis < 3; ++axis )
{
Clip3D_plane( pVerts, 1, axis, phwNumVerts, &pClipBox->m_vMin );
Clip3D_plane( pVerts, -1, axis, phwNumVerts, &pClipBox->m_vMax );
}
for ( u8 vert = 0; vert < *phwNumVerts; ++vert )
{
BoundingBox_Append( pBB3, &pVerts[vert] );
}
}

In general you can't escape computing intersection points between the sides of the triangle and those of the box. To get a correct result, you need to compute the intersection of the two shapes, for instance using the Sutherland-Hodgman algorithm, that you can specialize for the case of a triangle and a rectangle. If I am right, in the worst case you get an heptagon.
Then getting the AABB is no big deal.
Alternatively, you can implement a line-segment clipping algorithm against a poygonal (triangular or rectangular) window. A specialization to an AA window is the Cohen-Sutherland algorithm. Then clip all triangle sides against the rectangle and all rectangle sides against the triangle.

Related

Dashed border seems like its multiplying

I'm makking a Node.js app with Jimp. I have a function for selecting part of an image. It draws a rectangle in the area, writes the number of the selection in the middle and then draws a dashed border around the outside of the rectangle selection. The dashed border seems to be multiplying and I have no idea why. Here's the full code of the file:
imageManipulationUtil.js:
const Jimp = require("jimp");
module.exports = async (readPath, writePath, comments, callback) => {
const originalImage = await Jimp.read(readPath);
const font = await Jimp.loadFont(Jimp.FONT_SANS_32_BLACK);
// Please ignore this part. Focus on the other part (the functions I mentioned above).
const addedWidth = 500;
const commentsHeight = comments.reduce((commentsHeight, { comment }, i) => {
comments[i].comment = `${i + 1}. ${comment}`;
const textWidth = Jimp.measureText(font, comment);
const textHeight = Jimp.measureTextHeight(font, comment);
const lines = Math.ceil(textWidth / addedWidth);
const height = textHeight * lines;
return commentsHeight + height;
}, 0);
const imageHeight = commentsHeight + 10;
if (imageHeight > originalImage.getHeight())
originalImage.resize(Jimp.AUTO, imageHeight);
const newImage = new Jimp(
originalImage.getWidth() + addedWidth,
originalImage.getHeight(),
0xffffffff
);
// Some other code for another purpose
// !!! Important code START !!!
drawSelectionRects(comments, font, newImage);
async function drawSelectionRects(comments, font, image) {
comments.forEach(({ dimensions }) => {
image.scanQuiet(
dimensions.x,
dimensions.y,
dimensions.width,
dimensions.height,
(x, y, idx) => {
const color = {
r: image.bitmap.data[idx + 0],
g: image.bitmap.data[idx + 1],
b: image.bitmap.data[idx + 2],
a: image.bitmap.data[idx + 3] / 255,
};
const selectionColor = {
r: 187,
g: 187,
b: 187,
a: 187,
};
const newColor = blendColors(color, selectionColor);
const hexColor = Jimp.rgbaToInt(
newColor.r,
newColor.g,
newColor.b,
255
);
image.setPixelColor(hexColor, x, y);
}
);
dashedBorder(
image,
{ lineDash: [20, 5], lineWidth: 3, color: 0x1a53ffbb },
dimensions
);
});
comments.forEach(({ dimensions }, i) => {
const text = `${i + 1}`;
let textX =
dimensions.x + (dimensions.width - Jimp.measureText(font, text)) / 2;
let textY =
dimensions.y +
(dimensions.height - Jimp.measureTextHeight(font, text)) / 2;
image.print(font, textX, textY, text);
});
}
function blendColors(c1, c2) {
const stepPoint = c2.a / 255;
const r = c1.r + stepPoint * (c2.r - c1.r);
const g = c1.g + stepPoint * (c2.g - c1.g);
const b = c1.b + stepPoint * (c2.b - c1.b);
return { r, g, b };
}
function dashedBorder(
image,
{ lineDash, lineWidth, color },
{ x, y, width, height }
) {
let drawing = true,
passed = 0;
color = Jimp.intToRGBA(color);
// Top border
for (let i = x; i < x + width; i++) {
if (drawing) {
const pixelColor = Jimp.intToRGBA(image.getPixelColor(x, y));
const newColor = blendColors(pixelColor, color);
for (let k = 0; k < lineWidth; k++) {
image.setPixelColor(
Jimp.rgbaToInt(newColor.r, newColor.g, newColor.b, 255),
i,
y - k
);
}
}
passed++;
if (
(passed >= lineDash[0] && drawing) ||
(passed >= lineDash[1] && !drawing)
) {
drawing = !drawing;
passed = 0;
}
}
drawing = true;
// Right border
for (let j = y; j < y + height; j++) {
if (drawing) {
const pixelColor = Jimp.intToRGBA(image.getPixelColor(x + width, y));
const newColor = blendColors(pixelColor, color);
for (let k = 0; k < lineWidth; k++) {
image.setPixelColor(
Jimp.rgbaToInt(newColor.r, newColor.g, newColor.b, 255),
x + width + k,
j
);
}
}
passed++;
if (
(passed >= lineDash[0] && drawing) ||
(passed >= lineDash[1] && !drawing)
) {
drawing = !drawing;
passed = 0;
}
}
drawing = true;
// Bottom border
for (let i = x + width; i > x; i--) {
if (drawing) {
const pixelColor = Jimp.intToRGBA(image.getPixelColor(i, y + height));
const newColor = blendColors(pixelColor, color);
for (let k = 0; k < lineWidth; k++) {
image.setPixelColor(
Jimp.rgbaToInt(newColor.r, newColor.g, newColor.b, 255),
i,
y + height + k
);
}
}
passed++;
if (
(passed >= lineDash[0] && drawing) ||
(passed >= lineDash[1] && !drawing)
) {
drawing = !drawing;
passed = 0;
}
}
drawing = true;
// Left border
for (let j = y + height; j > y + lineWidth; j--) {
if (drawing) {
const pixelColor = Jimp.intToRGBA(image.getPixelColor(x, j));
const newColor = blendColors(pixelColor, color);
for (let k = 0; k < lineWidth; k++) {
image.setPixelColor(
Jimp.rgbaToInt(newColor.r, newColor.g, newColor.b, 255),
x - k,
j
);
}
}
passed++;
if (
(passed >= lineDash[0] && drawing) ||
(passed >= lineDash[1] && !drawing)
) {
drawing = !drawing;
passed = 0;
}
}
}
newImage.write(writePath);
callback();
};
// !!! Important code END !!!
The code exports a function that takes some parameters. The most important parameter is the comments parameter (specifically the dimensions of the comment). The comments param is an array of objects. The objects have a dimensions key which is the important one in this question.
The image uploaded:
Image recieved:
The problem that makes me think the image is multiplying is that in some places the border is more transparent than in other parts. Originally I thought that was just because of the image I used but then I switched it and noticed it was a real problem.
New full code:
const Jimp = require("jimp");
function dashedBorder(
image,
{ lineDash, lineWidth, color },
{ x, y, width, height }
) {
let drawing = true,
passed = 0,
outsideWidth = lineWidth - 1;
color = Jimp.intToRGBA(color);
// Top border
for (let i = x - outsideWidth; i < x + width + outsideWidth; i++) {
if (drawing) {
for (let k = 0; k < lineWidth; k++) {
image.setPixelColor(
Jimp.rgbaToInt(color.r, color.g, color.b, 255),
i,
y - k
);
}
}
passed++;
if (
(passed >= lineDash[0] && drawing) ||
(passed >= lineDash[1] && !drawing)
) {
drawing = !drawing;
passed = 0;
}
}
// Right border
for (
let j = y + lineWidth - outsideWidth;
j < y + height - (lineWidth - outsideWidth);
j++
) {
if (drawing) {
for (let k = 0; k < lineWidth; k++) {
image.setPixelColor(
Jimp.rgbaToInt(color.r, color.g, color.b, 255),
x + width + k - 1,
j
);
}
}
passed++;
if (
(passed >= lineDash[0] && drawing) ||
(passed >= lineDash[1] && !drawing)
) {
drawing = !drawing;
passed = 0;
}
}
// Bottom border
for (let i = x + width + lineWidth - outsideWidth; i > x - lineWidth; i--) {
if (drawing) {
for (let k = 0; k < lineWidth; k++) {
image.setPixelColor(
Jimp.rgbaToInt(color.r, color.g, color.b, 255),
i,
y + height + k - 1
);
}
}
passed++;
if (
(passed >= lineDash[0] && drawing) ||
(passed >= lineDash[1] && !drawing)
) {
drawing = !drawing;
passed = 0;
}
}
// Left border
for (let j = y + height - outsideWidth; j > y; j--) {
if (drawing) {
for (let k = 0; k < lineWidth; k++) {
image.setPixelColor(
Jimp.rgbaToInt(color.r, color.g, color.b, 255),
x - k,
j
);
}
}
passed++;
if (
(passed >= lineDash[0] && drawing) ||
(passed >= lineDash[1] && !drawing)
) {
drawing = !drawing;
passed = 0;
}
}
}
(async () => {
let image = await Jimp.read("./test.png");
dashedBorder(
image,
{ lineWidth: 3, lineDash: [20, 5], color: 0x1a53ffbb },
{ x: 0, y: 0, width: image.bitmap.width, height: image.bitmap.height }
);
image.write("./test-border.png");
})();
Image:

Unity - Infinite terrain gaps betwean chunks?

So I am creating an endless terrain.
I can create the terrain but my chunks have gaps betwean them and they don't align properly.
I think the problem might be caused by my Noise Generation script, but I am not sure.
This is my Noise Generation script
public static class Noise_GENERATOR
{
public static float[,] GenerateNoise(int chunkSize, int octaves, int seed, float noiseScale, float persistence, float lacunarity, Vector2 offset)
{
float[,] noiseMap = new float[chunkSize, chunkSize];
System.Random prng = new System.Random(seed);
Vector2[] octaveOffsets = new Vector2[octaves];
float maxPossibleHeight = 0;
float amplitude = 1;
float frequency = 1;
for (int i = 0; i < octaves; i++)
{
float offsetX = prng.Next(-100000, 100000) + offset.x;
float offsetY = prng.Next(-100000, 100000) + offset.y;
octaveOffsets[i] = new Vector2(offsetX, offsetY);
maxPossibleHeight += amplitude;
amplitude *= persistence;
}
if (noiseScale <= 0)
{
noiseScale = 0.0001f;
}
float maxLocalNoiseHeight = float.MinValue;
float minLocalNoiseHeight = float.MaxValue;
float halfWidth = chunkSize / 2f;
float halfHeight = chunkSize / 2f;
for (int y = 0; y < chunkSize; y++)
{
for (int x = 0; x < chunkSize; x++)
{
amplitude = 1;
frequency = 1;
float noiseHeight = 0;
for (int i = 0; i < octaves; i++)
{
float sampleX = (x-halfWidth + octaveOffsets[i].x) / noiseScale * frequency;
float sampleY = (y-halfHeight + octaveOffsets[i].y) / noiseScale * frequency;
float perlinValue = Mathf.PerlinNoise(sampleX, sampleY) * 2 - 1;
noiseHeight += perlinValue * amplitude;
amplitude *= persistence;
frequency *= lacunarity;
}
if (noiseHeight > maxLocalNoiseHeight)
{
maxLocalNoiseHeight = noiseHeight;
}
else if (noiseHeight < minLocalNoiseHeight)
{
minLocalNoiseHeight = noiseHeight;
}
noiseMap[x, y] = noiseHeight;
float normalizedHeight = (noiseMap[x, y] + 1) / (maxPossibleHeight / 0.9f);
noiseMap[x, y] = Mathf.Clamp(normalizedHeight, 0, int.MaxValue);
}
}
return noiseMap;
}
}
To Generate the height of a mesh, I am using Animation Curve and multiplying it by elevationScale variable.
float height = heightCurve.Evaluate(noiseMap[x, y]) * elevationScale;
I thought about accesing each Terrain chunk and getting the height of the edges and matching them together but that would look really weird and I don't know how to do it properly.
EDIT: Here just in case my Mesh generator script and how I am creating the Terrain chunk
public static class Mesh_GENERATOR
{
public static MeshData GenerateChunkMesh(int chunkSize,float[,] noiseMapData,float elevationScale,AnimationCurve terrainCurve,int LODlevel )
{
float[,] noiseMap = noiseMapData;
AnimationCurve heightCurve = new AnimationCurve(terrainCurve.keys);
//Setup variables
Vector3[] vertices = new Vector3[chunkSize * chunkSize];
int[] triangles = new int[(chunkSize - 1) * (chunkSize - 1) * 6];
Vector2[] uvs = new Vector2[chunkSize * chunkSize];
int triangle = 0;
int levelOfDetailIncrement = (LODlevel == 0) ? 1 : LODlevel * 2;
int numberOfVerticesPerRow = (chunkSize) / levelOfDetailIncrement + 1;
for (int y = 0; y < chunkSize; y++)
{
for (int x = 0; x < chunkSize; x++)
{
int i = y * chunkSize + x;
//Create vertices at position and center mesh
float height = heightCurve.Evaluate(noiseMap[x, y]) * elevationScale;
Vector2 percentPosition = new Vector2(x / (chunkSize - 1f), y / (chunkSize -1f ));
Vector3 vertPosition = new Vector3(percentPosition.x * 2 - 1, 0, percentPosition.y * 2 - 1) * chunkSize/2;
vertPosition.y = height;
vertices[i] = vertPosition;
uvs[i] = new Vector2((float)x / chunkSize, (float)y / chunkSize);
//Construct triangles
if (x != chunkSize - 1 && y != chunkSize - 1)
{
triangles[triangle + 0] = i + chunkSize;
triangles[triangle + 1] = i + chunkSize + 1;
triangles[triangle + 2] = i;
triangles[triangle + 3] = i + chunkSize + 1;
triangles[triangle + 4] = i + 1;
triangles[triangle + 5] = i;
triangle += 6;
}
}
}
MeshData meshData = new MeshData(chunkSize, vertices, triangles, uvs);
return meshData;
}
}
public class MeshData
{
public int chunkSize;
public Vector3[] vertices;
public int[] triangles;
public Vector2[] uvs;
public Mesh mesh;
public MeshData(int chunkSize,Vector3[] vertices,int[] triangles, Vector2[] uvs)
{
this.chunkSize = chunkSize;
this.vertices = vertices;
this.triangles = triangles;
this.uvs = uvs;
}
public Mesh CreateMesh()
{
if(mesh == null) { mesh = new Mesh(); } else { mesh.Clear(); }
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.uv = uvs;
mesh.RecalculateNormals();
return mesh;
}
}
And here is my TerrainChunk
public class TerrainChunk
{
GameObject meshObject;
Vector2 position;
Bounds bounds;
MeshRenderer meshRenderer;
MeshFilter meshFilter;
public TerrainChunk(Vector2 coord, int chunkSize, Transform parent,Material terrainMaterial)
{
position = coord * chunkSize;
bounds = new Bounds(position, Vector2.one * chunkSize);
Vector3 positionV3 = new Vector3(position.x , 0, position.y );
Debug.Log("CHUNK: COORD" + coord + "POSITION" + position + "POSITION3V" + positionV3);
meshObject = new GameObject("Terrain Chunk");
meshFilter = meshObject.AddComponent<MeshFilter>();
meshRenderer = meshObject.AddComponent<MeshRenderer>();
meshRenderer.material = terrainMaterial;
meshObject.transform.position = positionV3;
meshObject.transform.parent = parent;
SetVisible(false);
worldGenerator.RequestMapData(position,OnNoiseDataReceived);
}
void OnNoiseDataReceived(MapData mapData)
{
worldGenerator.RequestMeshData(mapData, OnMeshDataReceived);
}
void OnMeshDataReceived(MeshData meshData)
{
meshFilter.mesh = meshData.CreateMesh();
}
public void UpdateTerrainChunk(Vector2 viewerPosition, int maxRenderDistance)
{
float viewerDstFromNearestEdge = Mathf.Sqrt(bounds.SqrDistance(viewerPosition));
bool visible = viewerDstFromNearestEdge <= maxRenderDistance;
SetVisible(visible);
}
public void SetVisible(bool visible)
{
meshObject.SetActive(visible);
}
public bool IsVisible()
{
return meshObject.activeSelf;
}
}
}
If I undestand all your values and variables correctly.
The problem might lay in the Noise Generator.
You need to create the chunkSize to be bigger by 1 so if you are passing 250 you will need to pass 251, as the for loop in the Noise Generator stops at 249 and not 250. (I might be wrong about this ), If you do this the mesh generator will now have the right values for calculation.
So your chunksize variable should look like this
chunkSize = chunkSize + 1;
Now there will still be smaller gaps and the mesh will clip through each other, so to fix this you will need to position the Chunk and you do it this way ->
(If your coord serves as a direction in which the chunk will be created from your World generator object -> for example chunks pointing North will be with values x:0 y:1, chunks pointing West will be x:-1 y:0, NorthWest chunks x:-1 y:-1 and so on), you may need to change the 0.5f to your values so the chunks align properly.
Vector3 positionV3 = new Vector3(position.x + (coord.x + 0.5f), 0, position.y + (coord.y + 0.5f) );
There still may be some smaller gaps visible in the terrain, but this can be fixed by playing with the values, or you can try and access each Chunk and get the edge vertices and their heights and connect the chunks together this way.

Saving your canvas image

Im using clientcanvas to edit pictures in my app created with tabris. So far it's working quite well, but I got a problem to save the edited picture as a new image. Does anybody has any experience with that?
You need to convert the swt ImageData to an awt BufferedImage and save it. A util for this may look like this:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.WritableRaster;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.RGB;
public class ImageUtil {
public static BufferedImage convertToAWT( ImageData data ) {
BufferedImage imageToDraw = bgToAWT( data, data.width, data.height );
BufferedImage result = new BufferedImage( data.width, data.height, BufferedImage.TYPE_INT_RGB );
drawWhiteBackground( result );
Graphics graphics = result.getGraphics();
graphics.drawImage( imageToDraw, 0, 0, null );
graphics.dispose();
return result;
}
/*
* See
* http://m4tx.pl/en/2013/01/01/java-swt-to-awt-and-vice-versa-image-conversion
* -with-transparency-support/
*/
public static BufferedImage bgToAWT( ImageData data, int width, int height ) {
BufferedImage result = null;
ColorModel colorModel = null;
PaletteData palette = data.palette;
if( palette.isDirect ) {
BufferedImage bufferedImage = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB );
for( int y = 0; y < data.height; y++ ) {
for( int x = 0; x < data.width; x++ ) {
int pixel = data.getPixel( x, y );
RGB rgb = palette.getRGB( pixel );
bufferedImage.setRGB( x, y, data.getAlpha( x, y ) << 24
| rgb.red << 16
| rgb.green << 8
| rgb.blue );
}
}
result = bufferedImage;
} else {
RGB[] rgbs = palette.getRGBs();
byte[] red = new byte[ rgbs.length ];
byte[] green = new byte[ rgbs.length ];
byte[] blue = new byte[ rgbs.length ];
for( int i = 0; i < rgbs.length; i++ ) {
RGB rgb = rgbs[ i ];
red[ i ] = ( byte )rgb.red;
green[ i ] = ( byte )rgb.green;
blue[ i ] = ( byte )rgb.blue;
}
if( data.transparentPixel != -1 ) {
colorModel = new IndexColorModel( data.depth,
rgbs.length,
red,
green,
blue,
data.transparentPixel );
} else {
colorModel = new IndexColorModel( data.depth, rgbs.length, red, green, blue );
}
BufferedImage bufferedImage = new BufferedImage( colorModel,
colorModel.createCompatibleWritableRaster( width,
height ),
false,
null );
WritableRaster raster = bufferedImage.getRaster();
int[] pixelArray = new int[ 1 ];
for( int y = 0; y < data.height; y++ ) {
for( int x = 0; x < data.width; x++ ) {
int pixel = data.getPixel( x, y );
pixelArray[ 0 ] = pixel;
raster.setPixel( x, y, pixelArray );
}
}
result = bufferedImage;
}
return result;
}
private static void drawWhiteBackground( BufferedImage bufferedImage ) {
Graphics2D graphics = bufferedImage.createGraphics();
graphics.setColor( new Color( 255, 255, 255 ) );
graphics.fillRect( 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight() );
}
}

nlopt_add_equality_constraint doesn't work

I write a program,
to minimize:
f = x^2 + y^2
constrain:
c: x-1 < 0
ceq: x+y-5=0
I got answer:
x = 0.12219
y = 5.678
which is not satisfy ceq.
I don't know how to fix it.
My complete source code is here
main function is as follow:
int main()
{
nlopt_opt opt;
opt = nlopt_create(NLOPT_LD_MMA, 2); /* algorithm and dimensionality */
nlopt_set_min_objective(opt, myfunc, NULL);
nlopt_add_equality_constraint(opt, ceq1, NULL, 1e-8);
nlopt_add_inequality_constraint(opt, c1, NULL, 1e-8);
nlopt_set_xtol_rel(opt, 1e-4);
double x[2] = { 1.234, 5.678 }; /* some initial guess */
double minf; /* the minimum objective value, upon return */
if (nlopt_optimize(opt, x, &minf) < 0) {
printf("nlopt failed!\n");
}
else {
printf("found minimum at f(%g,%g) = %0.10g\n", x[0], x[1], minf);
}
nlopt_destroy(opt);
return 0;
}
update!!!!!
After reading the document, I found the algorithm "MMA" doesn't support "equal constraint."
To replace "MMA" with "SLSQP" might solve this problem.

Direct3D 11 Applying texture to sphere

I'm trying to apply a texture to sphere. I have used a 3d modelling software to create the sphere with vertices, normals and texcoords exported as .obj file. I parse the file and create a vertex buffer with the data. IDE is Visual C++ 2012.
The texture is a 512x256 jpg of earth (original, huh?)
It looks like this
which doesn't look as expected. Been experimenting with different UV mappings without luck.
Loading resource:
D3DX11CreateShaderResourceViewFromFile(dev, // the Direct3D device
L"earth.jpg",
NULL,
NULL,
&pTexture,
NULL);
devcon->PSSetShaderResources(0, 1, &pTexture);
Parsing file:
if (fileIn) {
while (fileIn) {
VERTEX vertex;
inChar = fileIn.get();
std::wstring string;
switch (inChar)
{
case '#':
inChar = fileIn.get();
while(inChar != '\n')
inChar = fileIn.get();
break;
case 'v':
inChar = fileIn.get();
if (inChar == ' ') //v - vert position
{
fileIn >> x >> y >> z;
vVector.push_back(D3DXVECTOR3(x, y, z));
vertCount++;
}
else if(inChar == 'n') //vn - vert normal
{
fileIn >> x >> y >> z;
nVector.push_back(D3DXVECTOR3(x, y, z));
normCount++;
}
else if(inChar == 't') //vt - vert tex coords
{
fileIn >> u >> v;
tVector.push_back(D3DXVECTOR2(u, v));
texCount++;
}
break;
case 'f': // assuming vectors are filled..
inChar = fileIn.get();
if (inChar != ' ')
break;
while (!fileIn.eof()) {
std::getline(fileIn, string);
size_t pos = 0;
while((pos = string.find(L"/", pos)) != std::string::npos)
{
string.replace(pos, 1, L" ");
pos++;
}
if (string.find(L"f ") != std::wstring::npos)
string = string.replace(0, 2, L"");
std::wistringstream iss(string);
iss.seekg(0, std::ios::beg);
while (iss >> i) {
iVector.push_back(i);
}
}
break;
}
}
}
int vv, vt, vn;
for (i = 0; i < iVector.size(); i += 3) {
vv = iVector.at(i) - 1;
vt = iVector.at(i + 1) - 1;
vn = iVector.at(i + 2) - 1;
VERTEX vertex;
vertex.X = vVector.at(vv).x;
vertex.Y = vVector.at(vv).y;
vertex.Z = vVector.at(vv).z;
vertex.U = tVector.at(vt).x;
vertex.V = tVector.at(vt).y;
vertex.Normal.x = nVector.at(vn).x;
vertex.Normal.y = nVector.at(vn).y;
vertex.Normal.z = nVector.at(vn).z;
vector.push_back(vertex);
}
Pixel shader:
float4 outputColor = (1.0f, 0.0f, 1.0f, 1.0f);
if (calc == 0) {
outputColor = lightAmbient;
float3 lightVector = lightPos.xyz - input.worldPosition.xyz;
float3 normalVector = input.normal.xyz;
float distance = length(lightVector);
//if (distance > range)
//return outputColor;
float diffuseBrightness = saturate(dot(normalize(normalVector), normalize(lightVector)));
outputColor += diffuseBrightness;
//outputColor *= lightAtt.x + (lightAtt.y * distance) + (lightAtt.z * (distance * distance));
outputColor = saturate(outputColor);
outputColor *= Texture.Sample(ss, input.texcoord);
}
return outputColor;
Any ideas? Help appreciated. OBJ file can be found here

Resources