Kd Tree or Bounding Box Not Working Properly - raytracing
Hope everyone is well.I am having a bit of an issue implementing the kd tree from pbrt v2.It's fast but all the normals on the model are wrong after rendering.The funny thing is if I change the values of pMin and pMax in the Bounding Box constructor,I get the correct model with the correct normals but the render takes substantially longer.I dont know what could be causing this.By the way pbrt v2 uses a left-handed coordinate system while I am using a right-handed coordinate system.I have tried changing my coordinate to left-handed and also importing models from a left-handed system instead of a right-handed system but the issue still remains.At one point it worked but the models positions were reversed.Its best to show you my code so u can better understand my dilemma.
*BOUNDING BOX CODE *
class BBox
{
public:
Point pMin,pMax;
BBox(){
pMin = Point(INFINITY,INFINITY,INFINITY);
pMax = Point(-INFINITY,-INFINITY,-INFINITY);
}
BBox(const Point& p) : pMin(p),pMax(p) { }
BBox(const Point& p1,const Point& p2) {
pMin = Point(min(p1.x,p2.x),min(p1.y,p2.y),min(p1.z,p2.z));
pMax = Point(max(p1.x,p2.x),max(p1.y,p2.y),max(p1.z,p2.z));
}
Point boxCentroid() const {
float x = (pMin.x+pMax.x)/2;
float y = (pMin.y+pMax.y)/2;
float z = (pMin.z+pMax.z)/2;
return Point(x,y,z);
}
BBox Union(const BBox &b,const Point& p) {
BBox ret = b;
ret.pMin.x = min(b.pMin.x,p.x);
ret.pMin.y = min(b.pMin.y,p.y);
ret.pMin.z = min(b.pMin.z,p.z);
ret.pMax.x = max(b.pMax.x,p.x);
ret.pMax.y = max(b.pMax.y,p.y);
ret.pMax.z = max(b.pMax.z,p.z);
return ret;
}
friend BBox Union(const BBox& b,const BBox& b2){
BBox ret;
ret.pMin.x = min(b.pMin.x, b2.pMin.x);
ret.pMin.y = min(b.pMin.y, b2.pMin.y);
ret.pMin.z = min(b.pMin.z, b2.pMin.z);
ret.pMax.x = max(b.pMax.x, b2.pMax.x);
ret.pMax.y = max(b.pMax.y, b2.pMax.y);
ret.pMax.z = max(b.pMax.z, b2.pMax.z);
return ret;
}
bool Overlaps(const BBox &b) const {
bool x = (pMax.x >= b.pMin.x) && (pMin.x <= b.pMax.x);
bool y = (pMax.y >= b.pMin.y) && (pMin.y <= b.pMax.y);
bool z = (pMax.z >= b.pMin.z) && (pMin.z <= b.pMax.z);
return (x && y && z);
}
bool Inside(const Point& pt) const {
return (pt.x >= pMin.x && pt.x <= pMax.x &&
pt.y >= pMin.y && pt.y <= pMax.y &&
pt.z >= pMin.z && pt.z <= pMax.z);
}
void Expand(float delta) {
pMin -= Vector(delta,delta,delta);
pMax += Vector(delta,delta,delta);
}
float SurfaceArea() const {
Vector d = pMax - pMin;
return 2.f * (d.x*d.y + d.x*d.z + d.y*d.z);
}
float Volume() const {
Vector d = pMax - pMin;
return d.x*d.y*d.z;
}
int MaximumExtent() const {
Vector diag = pMax - pMin;
if (diag.x > diag.y && diag.x > diag.z)
return 0;
else if (diag.y > diag.z)
return 1;
else
return 2;
}
const Point &operator[](int i) const {
//Assert(i == 0 || i == 1);
return (&pMin)[i];
}
Point &operator[](int i) {
//Assert(i == 0 || i == 1);
return (&pMin)[i];
}
Point Lerp(float tx, float ty, float tz) const {
return Point(::Lerp(tx, pMin.x, pMax.x), ::Lerp(ty, pMin.y, pMax.y),
::Lerp(tz, pMin.z, pMax.z));
}
Vector Offset(const Point &p) const {
return Vector((p.x - pMin.x) / (pMax.x - pMin.x),
(p.y - pMin.y) / (pMax.y - pMin.y),
(p.z - pMin.z) / (pMax.z - pMin.z));
}
void BBox::BoundingSphere(Point *c, float *rad) const {
*c = pMin * 0.5f + pMax * 0.5f;
*rad = Inside(*c) ? Distance(*c, pMax) : 0.f;
}
bool IntersectP(const Ray &ray,float *hitt0,float *hitt1) const {
float t0 = 0.00001f, t1 = INFINITY;
for (int i = 0; i < 3; ++i) {
// Update interval for _i_th bounding box slab
float invRayDir = 1.f / ray.d[i];
float tNear = (pMin[i] - ray.o[i]) * invRayDir;
float tFar = (pMax[i] - ray.o[i]) * invRayDir;
// Update parametric interval from slab intersection $t$s
if (tNear > tFar) swap(tNear, tFar);
t0 = tNear > t0 ? tNear : t0;
t1 = tFar < t1 ? tFar : t1;
if (t0 > t1) return false;
}
if (hitt0) *hitt0 = t0;
if (hitt1) *hitt1 = t1;
return true;
}
};
If I use the current default BBox constructor with the above pMin and pMax values.I get this
But if I change it to
pMin = Point(-INFINITY,-INFINITY,-INFINITY);
pMax = Point(INFINITY,INFINITY,INFINITY);
I get the right model.This...
But it takes substantially longer.(7secs to 51 minutes) You see the issue ??? Anyways I need help.Any help is appreciated.Thanks
Here is the rest of the necessary code (KD-TREE) and (CAMERA)
*KD TREE CODE *
struct BoundEdge
{
//BoundEdge Methods
BoundEdge() { }
BoundEdge(float tt,int pn,bool starting){
t = tt;
primNum = pn;
type = starting ? START : END;
}
bool operator<(const BoundEdge &e) const {
if (t == e.t)
return (int)type < (int)e.type;
else return t < e.t;
}
float t;
int primNum;
enum { START,END } type;
};
struct KdAccelNode
{
void initLeaf(uint32_t *primNums,int np,MemoryArena &arena);
void initInterior(uint32_t axis,uint32_t ac,float s)
{
split = s;
flags = axis;
aboveChild |= (ac<<2);
}
float SplitPos() const { return split; }
uint32_t nPrimitives() const { return nPrims >> 2; }
uint32_t SplitAxis() const { return flags & 3; }
bool isLeaf() const { return (flags & 3)==3; }
uint32_t AboveChild() const { return aboveChild >> 2; }
union{
float split;
uint32_t onePrimitive;
uint32_t *primitives;
};
private:
union{
uint32_t flags;
uint32_t nPrims;
uint32_t aboveChild;
};
};
struct KdToDo{
const KdAccelNode *node;
float tMIN,tMAX;
};
class KdTreeAccel : public Primitive
{
public:
KdTreeAccel(const vector<Primitive*> &p,int icost,int tcost,float ebonus,int maxp,int md)
:primitives(p),isectCost(icost),traversalCost(tcost),emptyBonus(ebonus),maxPrims(maxp),maxDepth(md)
{
//Build Kd-Tree
nextFreeNode = nAllocedNodes = 0;
if(maxDepth <= 0)
maxDepth = Round2Int(8+1.3f * Log2Int(float(primitives.size())));
//<Compute Bounds>
vector<BBox> primBounds;
primBounds.reserve(primitives.size());
for(uint32_t i=0;i<primitives.size();++i)
{
BBox b = primitives[i]->BoxBound();
bounds = Union(bounds,b);
primBounds.push_back(b);
}
//<Allocate Working Memory>
BoundEdge *edges[3];
for(int i=0;i<3;++i)
edges[i] = new BoundEdge[2*primitives.size()];
uint32_t *prims0 = new uint32_t[primitives.size()];
uint32_t *prims1 = new uint32_t[(maxDepth+1) * primitives.size()];
//<Initialize primNums
uint32_t *primNums = new uint32_t[primitives.size()];
for(uint32_t i=0;i<primitives.size();++i)
primNums[i] = i;
//<Start Recursive Construction
buildTree(0,bounds,primBounds,primNums,primitives.size(),maxDepth,edges,prims0,prims1);
//<Free Memory
delete[] primNums;
for (int i = 0; i < 3; ++i)
delete[] edges[i];
delete[] prims0;
delete[] prims1;
}
virtual bool intersect(const Ray& r,float t_min,float t_max,primitive_record &rec) const;
virtual bool intersect_p(const Ray& r,float t_min,float t_max) const;
virtual float area() const;
virtual Vector _normal(const Point& in_point) const;
virtual Point randomSamplePoint() const;
virtual BBox BoxBound() const ;
virtual Point centroid() const ;
private:
void buildTree(int nodeNum,const BBox &nodeBounds,const vector<BBox> &allPrimBounds,uint32_t *primNums,
int nPrimitives,int depth,BoundEdge *edges[3],uint32_t *prims0,uint32_t *prims1,
int badRefines=0);
int isectCost,traversalCost,maxPrims,maxDepth;
float emptyBonus;
vector<Primitive*> primitives;
KdAccelNode *nodes;
int nAllocedNodes,nextFreeNode;
BBox bounds;
MemoryArena arena;
};
void KdAccelNode::initLeaf(uint32_t *primNums,int np,MemoryArena &arena)
{
flags = 3;
nPrims |= (np<<2);
//Store primitive id for leaf node
if(np == 0)
onePrimitive = 0;
else if(np == 1)
onePrimitive = primNums[0];
else{
primitives = arena.Alloc<uint32_t>(np);
for(int i=0;i<np;++i)
primitives[i] = primNums[i];
}
}
void KdTreeAccel::buildTree(int nodeNum,const BBox &nodeBounds,const vector<BBox> &allPrimBounds,uint32_t *primNums,
int nPrimitives,int depth,BoundEdge *edges[3],uint32_t *prims0,uint32_t *prims1,
int badRefines)
{
//Get Next Free Node
assert(nodeNum == nextFreeNode);
if(nextFreeNode == nAllocedNodes){
int nAlloc = max(2*nAllocedNodes,512);
KdAccelNode *n = AllocAligned<KdAccelNode>(nAlloc);
if(nAllocedNodes > 0){
memcpy(n,nodes,nAllocedNodes*sizeof(KdAccelNode));
FreeAligned(nodes);
}
nodes = n;
nAllocedNodes = nAlloc;
}
++nextFreeNode;
//Initialize leaf Node
if(nPrimitives <= maxPrims || depth == 0){
nodes[nodeNum].initLeaf(primNums,nPrimitives,arena);
return;
}
//Initialize Interior Node
//--Choose split axis
int bestAxis = -1, bestOffset = -1;
float bestCost = INFINITY;
float oldCost = isectCost * float(nPrimitives);
float totalSA = nodeBounds.SurfaceArea();
float invTotalSA = 1.f / totalSA;
Vector d = nodeBounds.pMax - nodeBounds.pMin;
uint32_t axis = nodeBounds.MaximumExtent();
int retries = 0;
retrySplit:
for (int i = 0; i < nPrimitives; ++i) {
int pn = primNums[i];
const BBox &bbox = allPrimBounds[pn];
edges[axis][2*i] = BoundEdge(bbox.pMin[axis], pn, true);
edges[axis][2*i+1] = BoundEdge(bbox.pMax[axis], pn, false);
}
sort(&edges[axis][0], &edges[axis][2*nPrimitives]);
int nBelow = 0, nAbove = nPrimitives;
for (int i = 0; i < 2*nPrimitives; ++i) {
if (edges[axis][i].type == BoundEdge::END) --nAbove;
float edget = edges[axis][i].t;
if (edget > nodeBounds.pMin[axis] &&
edget < nodeBounds.pMax[axis]) {
//Compute cost for split at ith edge
uint32_t otherAxis0 = (axis + 1) % 3, otherAxis1 = (axis + 2) % 3;
float belowSA = 2 * (d[otherAxis0] * d[otherAxis1] +
(edget - nodeBounds.pMin[axis]) *
(d[otherAxis0] + d[otherAxis1]));
float aboveSA = 2 * (d[otherAxis0] * d[otherAxis1] +
(nodeBounds.pMax[axis] - edget) *
(d[otherAxis0] + d[otherAxis1]));
float pBelow = belowSA * invTotalSA;
float pAbove = aboveSA * invTotalSA;
float eb = (nAbove == 0 || nBelow == 0) ? emptyBonus : 0.f;
float cost = traversalCost +
isectCost * (1.f - eb) * (pBelow * nBelow + pAbove * nAbove);
if (cost < bestCost) {
bestCost = cost;
bestAxis = axis;
bestOffset = i;
}
}
if (edges[axis][i].type == BoundEdge::START) ++nBelow;
}
assert(nBelow == nPrimitives && nAbove == 0);
//--Create leaf if np good splits found
if (bestAxis == -1 && retries < 2) {
++retries;
axis = (axis+1) % 3;
goto retrySplit;
}
if (bestCost > oldCost) ++badRefines;
if ((bestCost > 4.f * oldCost && nPrimitives < 16) ||
bestAxis == -1 || badRefines == 3) {
nodes[nodeNum].initLeaf(primNums, nPrimitives, arena);
return;
}
//--Classify primitives with respect to split
int n0 = 0, n1 = 0;
for (int i = 0; i < bestOffset; ++i)
if (edges[bestAxis][i].type == BoundEdge::START)
prims0[n0++] = edges[bestAxis][i].primNum;
for (int i = bestOffset+1; i < 2*nPrimitives; ++i)
if (edges[bestAxis][i].type == BoundEdge::END)
prims1[n1++] = edges[bestAxis][i].primNum;
//--Recursively initialize children nodes
float tsplit = edges[bestAxis][bestOffset].t;
BBox bounds0 = nodeBounds, bounds1 = nodeBounds;
bounds0.pMax[bestAxis] = bounds1.pMin[bestAxis] = tsplit;
buildTree(nodeNum+1, bounds0,
allPrimBounds, prims0, n0, depth-1, edges,
prims0, prims1 + nPrimitives, badRefines);
uint32_t aboveChild = nextFreeNode;
nodes[nodeNum].initInterior(bestAxis, aboveChild, tsplit);
buildTree(aboveChild, bounds1, allPrimBounds, prims1, n1,
depth-1, edges, prims0, prims1 + nPrimitives, badRefines);
}
bool KdTreeAccel::intersect(const Ray& r,float t_min,float t_max,primitive_record &rec) const {
//Compute initial Parametric range of ray inside kd-tree extent
float tMIN,tMAX;
if(!bounds.IntersectP(r,&tMIN,&tMAX))
return false;
//Prepare to traverse kd-tree for ray
Vector invDir(1.f/r.d.x,1.f/r.d.y,1.f/r.d.z);
#define MAX_TODO 64
KdToDo todo[MAX_TODO];
int todoPos = 0;
//Traverse kd-tree nodes in order for ray
bool hit = false;
const KdAccelNode *node = &nodes[0];
while (node != NULL) {
if(t_max < tMIN) break;
if(!node->isLeaf())
{
//Process kd-tree interior node
int axis = node->SplitAxis();
float tplane = (node->SplitPos() - r.o[axis]) * invDir[axis];
const KdAccelNode *firstChild, *secondChild;
int belowFirst = (r.o[axis] < node->SplitPos()) ||
(r.o[axis] == node->SplitPos() && r.d[axis] <= 0);
if (belowFirst) {
firstChild = node + 1;
secondChild = &nodes[node->AboveChild()];
}
else {
firstChild = &nodes[node->AboveChild()];
secondChild = node + 1;
}
if (tplane > tMAX || tplane <= 0)
node = firstChild;
else if (tplane < tMIN)
node = secondChild;
else {
todo[todoPos].node = secondChild;
todo[todoPos].tMIN = tplane;
todo[todoPos].tMAX = tMAX;
++todoPos;
node = firstChild;
tMAX = tplane;
}
}
else
{
//Check for intersections inside leaf node
uint32_t nPrimitives = node->nPrimitives();
if (nPrimitives == 1) {
primitive_record tempRec;
Primitive* prim = primitives[node->onePrimitive];
//Check one prim inside leaf node
if(prim->intersect(r,t_min,t_max,tempRec))
{
rec = tempRec;
hit = true;
}
}
else {
primitive_record tempRec;
float closest_so_far = t_max;
uint32_t *prims = node->primitives;
for (uint32_t i = 0; i < nPrimitives; ++i)
{
//Check one prim inside leaf node
if(primitives[prims[i]]->intersect(r,t_min,closest_so_far,tempRec))
{
hit = true;
closest_so_far = tempRec.t;
rec = tempRec;
}
}
}
//Grab next node to process from todo list
if (todoPos > 0) {
--todoPos;
node = todo[todoPos].node;
tMIN = todo[todoPos].tMIN;
tMAX = todo[todoPos].tMAX;
}
else
break;
}
}
return hit;
}
*CAMERA CODE *
Vector random_in_unit_disk() {
Vector p;
do{
p = 2.f*Vector(drand48(),drand48(),0)-Vector(1.f,1.f,0.f);
}while(Dot(p,p) >= 1.f);
return p;
}
class Camera {
public:
Vector lower_left_corner;
Vector horizontal;
Vector vertical;
Point origin;
Vector u,v,w;
float lens_radius; //Focus
float time0,time1;
Camera(Point lookfrom,Point lookat,Vector vup,
float vfov,float aspect,float aperture,float focus_dist,float t0,float t1){
time0 = t0;
time1 = t1;
lens_radius = aperture/2;
float theta = vfov*M_PI/180.f;
float half_height = tanf(theta/2.f);
float half_width = aspect*half_height;
origin = lookfrom;
w = Normalize(lookfrom - lookat);
u = Normalize(Cross(vup,w));
v = Cross(w,u);
lower_left_corner = toVector(origin) - half_width*focus_dist*u - half_height*focus_dist*v - focus_dist*w;
horizontal = 2*half_width*focus_dist*u;
vertical = 2*half_height*focus_dist*v;
}
Ray get_ray(float s,float t) {
Vector rd = lens_radius*random_in_unit_disk();
Vector offset = u * rd.x + v * rd.y;
float time = time0 + drand48()*(time1-time0);
return Ray(origin + offset,lower_left_corner + s*horizontal + t*vertical - toVector(origin) - offset,time);
}
};
Related
Change variable in array coded with processing
Help! I'm drawing a sketch with randomized letters that fill the screen. The code issue is with my for (int i = 0; i < I1; i++) { targets = tX + i * ts; targets2 = tY; } else { runTowards = false; for (int i = 0; i < I1; i++) { targets = random(ts, width - ts); targets2 = random(ts, height - ts);` ** I need to update i within the for loop to denote the array letters' locations. The error returns a type mismatch, "float" does not match with int[] How do I update the i within the for loop?/ (the targets= and targets2=) Here is the code** String message = "a,b,c,d,e,f"; int []positions = new int [0]; int[]positions2= new int[1]; int []targets = new int [0] ; int [] targets2= new int[1]; int I1= message.length(); boolean runTowards = true; float runSpeed = 100; float restSpeed = 1; float currentSpeed = restSpeed; float ts = 64; boolean thisHasReached; float bk; float elapsedTime; boolean allHaveReached; float pauseTime = 1000; float distX; float distY; float changeX; float changeY; float tX; float tY; float reachedTargetAt = 0; boolean hasReachedTarget = true; void setup() { size (600,600); background(255); if ((I1 > targets.length) && (I1 > positions.length)){ pickNewTarget(); } } void draw() { elapsedTime = millis() - reachedTargetAt; if (elapsedTime > pauseTime) { pickNewTarget(); } drawChars(); updatePositions(); updateCurrentSpeed(); } void drawChars() { for (int i = 0; i < I1; i++) { text(message.charAt(i),positions[i], positions[i]); } } void updatePositions() { allHaveReached = true; thisHasReached = false; for (int i = 0; i < I1; i++) { distX = abs(positions[i] - targets[i]); distY = abs(positions2[i] - targets2[i]); changeX = random(currentSpeed); changeY = random(currentSpeed); thisHasReached = changeX > distX && changeY > distY; if (positions[i] > targets[i]) { changeX = -changeX; } if (positions2[i] > targets2[i]) { changeY = -changeY; } positions[i] += changeX; positions2[i] += changeY; allHaveReached = allHaveReached && thisHasReached; } if ((!hasReachedTarget) && (allHaveReached)) { hasReachedTarget = true; reachedTargetAt = millis(); } } void updateCurrentSpeed() { if (hasReachedTarget) { if (currentSpeed >= restSpeed) { currentSpeed -= (currentSpeed - restSpeed) * 9; } else { currentSpeed += 1; } } else { if (currentSpeed <= runSpeed) { currentSpeed += (runSpeed - currentSpeed) * 0.25; } else { currentSpeed -= 1; } } } void pickNewTarget() { if (!runTowards && random(1) > 0.75) { runTowards = true; tX = random(ts, width - 3 * ts); tY = random(ts, height - ts); for (int i = 0; i < I1; i++) { targets = tX + i * ts; targets2 = tY; } } else { runTowards = false; for (int i = 0; i < I1; i++) { targets = random(ts, width - ts); targets2 = random(ts, height - ts); } } hasReachedTarget = false; }
Please look at this reference for random(): https://processing.org/reference/random_.html. Note that it states "If two parameters are specified, the function will return a float with a value between the two values." You got the error message because you tried to mix ints and floats. You can correct it by changing the array types from int to float, eg. float[] targets = new float[80] ; float[] targets2= new float[80]; You'll also need to make those arrays large enough to handle the size of your data or you'll wind up with another error that the array length has been overrun. Then change the loop to reflect that you are adding data to the arrays ([i]): void pickNewTarget() { if (!runTowards && random(1) > 0.75) { runTowards = true; tX = random(ts, width - 3 * ts); tY = random(ts, height - ts); for (int i = 0; i < I1; i++) { targets[i] = tX + i * ts; targets2[i] = tY; } } else { runTowards = false; for (int i = 0; i < I1; i++) { targets[i] = random(ts, width - ts); targets2[i] = random(ts, height - ts); } } hasReachedTarget = false; } Also need to add a fill() for the text characters or you will see a blank screen.
How to create a line in a grid using Bresenham's line algorithm in Processing
I want to create a line using Bresenham's algorithm , but the only line that works is a horizontal line from left to right, lines pointing upwards do not work at all and lines drawn diagonally downwards appear in the wrong places, the more vertical the line, the more the distance between the mouse position changes and the drawn line up to a maximum of 3 cells. I'm using java and processing library. This is the link to all relevant code . Main code is this: void lineDrawing() { int deltaX = mouseNewCordX - mouseOldCordX, deltaY = mouseNewCordY - mouseOldCordY; int gradient = deltaY + deltaY, error = gradient - deltaX; if (abs(deltaY) < abs(deltaX)) { if (mouseOldCordX > mouseNewCordX) { plotLineLow(mouseOldCordX, mouseOldCordY, deltaX, deltaY, gradient, error); } else { plotLineLow(mouseNewCordX, mouseNewCordY, deltaX, deltaY, gradient, error); } } else { if (mouseOldCordY > mouseNewCordY) { plotLineHigh(mouseOldCordX, mouseOldCordY, deltaX, deltaY, gradient, error); } else { plotLineHigh(mouseNewCordX, mouseNewCordY, deltaX, deltaY, gradient, error); } } } void plotLineLow(int x0, int y0, int deltaX, int deltaY, int gradient, int error) { int yIncrease = 1; if (deltaY < 0) { yIncrease = -1; deltaY = -deltaY; } for (int x = mouseOldCordX; x <= mouseNewCordX; x += 1) { world[x][y0].state = selectedState; error += gradient; if (error >= 0) { y0 += yIncrease; error -= (deltaX + deltaX); } } } void plotLineHigh(int x0, int y0, int deltaX, int deltaY, int gradient, int error) { int xIncrease = 1; if (deltaX < 0) { xIncrease = -1; deltaX = -deltaX; } for (int y = mouseOldCordY; y <= mouseNewCordY; y += 1) { world[x0][y].state = selectedState; error += gradient; if (error >= 0) { x0 += xIncrease; error -= (deltaY + deltaY); } } }
I was able to use wikipedia to create a code that works: void lineDrawing() { int xIncrease = mouseOldCordX < mouseNewCordX ? 1 : -1; int yIncrease = mouseOldCordY < mouseNewCordY ? 1 : -1; int deltaX = abs(mouseNewCordX - mouseOldCordX); int deltaY = -abs(mouseNewCordY - mouseOldCordY); int error = deltaX + deltaY; while (true) { world[mouseOldCordX][mouseOldCordY].state = selectedState; if ((mouseOldCordX == mouseNewCordX) && (mouseOldCordY == mouseNewCordY)) break; int doubleError = 2 * error; if (doubleError >= deltaY) { error += deltaY; mouseOldCordX += xIncrease; } if (doubleError <= deltaX) { error += deltaX; mouseOldCordY += yIncrease; } } }
How to refresh OnPaint() function; Window Update is not working
This is my code: void CChildView::OnPaint() { CPaintDC dc(this); CBitmap b; b.LoadBitmap(IDB_BITMAP1); CDC memdc; memdc.CreateCompatibleDC(&dc); auto prev = memdc.SelectObject(&b); BITMAP bmp; b.GetBitmap(&bmp); int bitmap_height = bmp.bmHeight; int bitmap_width = bmp.bmWidth; if (!painted) { nrows = divide(bitmap_height, 8); ncols = divide(bitmap_width, 8); piece_height = bitmap_height / nrows; piece_width = bitmap_width / ncols; int number_of_tiles = nrows * ncols; positions.resize(number_of_tiles); std::iota(positions.begin(), positions.end(), 0); empty = positions.size() - 1;//prazna pločica je zadnja std::shuffle(positions.begin(), positions.end(), std::mt19937{ std::random_device{}() }); painted = true; } for (int i = 0; i < positions.size()-1; ++i) { int row_dest = positions[i] / ncols; int col_dest = positions[i] % ncols; int row_src = i / ncols; int col_src = i % ncols; int x_src = col_src * piece_width; int y_src = row_src * piece_height; int x_dest = col_dest * piece_width; int y_dest = row_dest * piece_height; dc.BitBlt(x_dest, y_dest, piece_width, piece_height, &memdc, x_src, y_src, SRCCOPY); dc.SelectObject(prev); } } void CChildView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call def CWnd::OnLButtonDown(nFlags, point); //koordinate gdje je korisnik kliknuo int row = point.y / piece_height; int col = point.x / piece_width; int empty_row = empty / ncols; int empty_col = empty % ncols; bool slide = false; switch (abs(row - empty_row)) { case 1: if (abs(col==empty_col)) slide = true; break; case 0: if (abs(col-empty_col==1)) slide = true; break; } if (slide) { int old_index = row * ncols + col; positions[old_index] = positions[empty]; empty = old_index; CWnd::InvalidateRect(NULL, FALSE); CWnd::UpdateWindow(); } } I am trying to write a program that is called SlidingPuzzle. I managed to divide a bitmap into rectangles and shuffle them randomly. However, when I click on a rectangle there is no change. I suppose that UpdateWindow() is not working. It should refresh OnPaint() function. Can someone please help me, what am I doing wrong?
Processing Image Load Error
I've added a background image to my processing file which works fine when I run it in Processing locally, however, I'm receiving this error in console when I host the file: Uncaught Error using image in background(): PImage not loaded. I can't find anywhere why this may be happening. Please see my code below: Particle p = new Particle(); final int LIGHT_FORCE_RATIO = 70; final int LIGHT_DISTANCE= 70 * 50; final int BORDER = 100; float baseRed, baseGreen, baseBlue; float baseRedAdd, baseGreenAdd, baseBlueAdd; final float RED_ADD = 3.2; final float GREEN_ADD = 1.7; final float BLUE_ADD = 4.3; float boxX, boxY; float widthSize = width; int rectWidth = 915; int rectHeight = 197; PImage img; void setup() { img = loadImage("https://s3.amazonaws.com/zcom-media/sites/a0iE000000QK9yZIAT/media/mediamanager/bannerbg.jpg"); background(img); size(1840, 400); // surface.setResizable(true); noCursor(); //img = loadImage("flowtoy.jpg"); baseRed = 0; baseRedAdd = RED_ADD; baseGreen = 0; baseGreenAdd = GREEN_ADD; baseBlue = 0; baseBlueAdd = BLUE_ADD; boxX = width/2; boxY = height/2; img.loadPixels(); for (int i = 0; i < img.pixels.length; i++) { img.pixels[i] = color(0, 90, 102); } img.updatePixels(); } void draw() { //image(img, 400, 100, img.width/2, img.height/2); if (mouseX>boxX-rectWidth && mouseX<boxX+rectWidth && mouseY>boxY-rectHeight && mouseY<boxY+rectHeight) { //saveFrame("output/LightDrawing_####.png"); baseRed += baseRedAdd; baseGreen += baseGreenAdd; baseBlue += baseBlueAdd; colorOutCheck(); p.move(mouseX, mouseY); int tRed = (int)baseRed; int tGreen = (int)baseGreen; int tBlue = (int)baseBlue; tRed *= tRed; tGreen *= tGreen; tBlue *= tBlue; loadPixels(); int left = max(0, p.x - BORDER); int right = min(width, p.x + BORDER); int top = max(0, p.y - BORDER); int bottom = min(height, p.y + BORDER); for (int y = top; y < bottom; y++) { for (int x = left; x < right; x++) { int pixelIndex = x + y * width; int r = pixels[pixelIndex] >>16 & 0xFF; int g = pixels[pixelIndex] >> 8 & 0xFF; int b = pixels[pixelIndex] & 0xFF; int dx = x - p.x; int dy = y - p.y; int distance = (dx *dx ) + (dy* dy); if (distance < LIGHT_DISTANCE) { int fixFistance = distance * LIGHT_FORCE_RATIO; if (fixFistance == 0) { fixFistance = 1; } r = r + tRed / fixFistance; g = g + tGreen / fixFistance; b = b + tBlue / fixFistance; } pixels[x + y * width] = color(r, g, b); } } updatePixels(); } else { setup(); } //updatePixels(); } void colorOutCheck() { if (baseRed < 10) { baseRed = 10; baseRedAdd *= -1; } else if (baseRed > 255) { baseRed = 255; baseRedAdd *= -1; } if (baseGreen < 10) { baseGreen = 10; baseGreenAdd *= -1; } else if (baseGreen > 255) { baseGreen = 255; baseGreenAdd *= -1; } if (baseBlue < 10) { baseBlue = 10; baseBlueAdd *= -1; } else if (baseBlue > 255) { baseBlue = 255; baseBlueAdd *= -1; } } void mousePressed() { setup(); } class Particle { int x, y; float vx, vy; //float slowLevel; Particle() { x = (int)3; y = (int)2; // slowLevel = random(100) + 1; } void move(float targetX, float targetY) { vx = (targetX - x) ; vy = (targetY - y) ; x = (int)(x + vx); y = (int)(y + vy); } } Can anybody explain why this may be happening? It's much appreciated, thank you.
I assume by 'hosting the file' you mean running the sketch at www.openprocessing.org. There are two problem with your code: Using background() inside setup. This will not work, you will get the error you mentioned. You can try moving that to draw(). Using an image which is hosted in another server. You should host your own images. A workaround to problem 2 is to store the image as a base64 encoded string. String uriBase64 = "data:image/jpeg;base64,/9j/4AAQSkZJRgA"; img = loadImage(uriBase64); Full example here: https://www.openprocessing.org/sketch/511424
Why do all the vectors in my loop get rotated in this processing code
I have a bug in a simple code which I am building. The code grows lines from nodes. Each node is two points and a line connecting the two. Each node can grow once and growth is handled in a growth function Part of growth function of the node class has a conditional that rotates the direction of the node (so the lines are slightly wavy) and for some reason all of the nodes get rotated in the way I have written the code. Can someone point out the undoubtedly simple error I have made? Code: Node[] ns; int nodeCount; void setup() { size(1024, 1024, P3D); background(255); stroke(0); frameRate(60); fill(0); nodeCount = int(10000); ns = new Node[nodeCount]; for(int i = 0; i < nodeCount; i++){ ns[i] = new Node(i, 0, 0, 0, 0, 0, new PVector(0, 0), false, false, false); } for(int i = 0; i < 1; i++){ ns[i] = new Node(i, random(float(width)), random(float(height)), 5, 0, random(100), new PVector(10, 10).rotate(random(-PI/2, PI/2)), true, false, true); } } void draw() { background(255); //print("frame "); for ( Node n: ns ){ if ( n.Active ) { //print(n.index, " "); n.display(); if ( n.Growth ){ n.grow(); } } if( n.Init ){ n.init(); } } } class Node { int index; float xi, yi, size, theta, noiseoff; PVector dir; Boolean Active, Growth, Init; Node(int ind, float x, float y, float s, float t, float n, PVector d, Boolean A, Boolean G, Boolean I) { index = ind; xi = x; yi = y; size = s; theta = t; noiseoff = n; dir = d; Active = A; Growth = G; Init = I; } void display(){ strokeWeight(0); ellipse(xi, yi, size, size); ellipse(xi + dir.x, yi + dir.y, size, size); strokeWeight(size); line(xi, yi, xi + dir.x, yi + dir.y); //xi = xi + dir.x; //yi = yi + dir.y; } void grow(){ boolean done = false; int i = index + 1; PVector tempDir = new PVector(0, 0); tempDir = dir; while ( !done & i < nodeCount & Growth ) { if ( ns[i].Active == false ) { if( random(100) > 85 ){ noiseoff += 0.01; theta = map(noise(noiseoff), 0, 1, -PI/12, PI/12); tempDir.rotate(theta); } ns[i] = new Node(i, xi + tempDir.x, yi + tempDir.y, size, theta, noiseoff, tempDir, true, false, true); Growth = false; done = true; if (i == nodeCount - 1 ) { done = true; } } i++; if (i == nodeCount ) { done = true; } } i++; } void init(){ Growth = true; Init = false; } } Another version that introduces createNode() method to remove the loop over the node array within the node class (still has the bug): Node[] ns; int nodeCount; void setup() { size(1024, 1024, P3D); background(255); stroke(0); frameRate(60); fill(0); nodeCount = int(10000); ns = new Node[nodeCount]; // Initialize array with blank nodes for(int i = 0; i < nodeCount; i++){ ns[i] = new Node(i, 0, 0, 0, 0, 0, new PVector(0, 0), false, false, false); } // Create Root node createNode(random(float(width)), random(float(height)), 5, 0, random(100), new PVector(2.5, 2.5).rotate(random(-PI/2, PI/2)), true, false, true); } void draw() { background(255); for ( Node n: ns ){ if ( n.Active ) { // Draw active nodes n.display(); // Grow nodes which haven't grown before if ( n.Growth ){ n.grow(); } } // Initialize nodes which were grown last time step (so that they can grown in the subsequent timestep) if( n.Init ){ n.init(); } } } // Wrapper function that looks for a free row in the node array to create a new node void createNode(float x, float y, float s, float t, float n, PVector d, Boolean A, Boolean G, Boolean I){ float xi, yi, size, theta, noiseoff; PVector dir; Boolean Active, Growth, Init, done; int i; xi = x; yi = y; size = s; theta = t; noiseoff = n; dir = d; Active = A; Growth = G; Init = I; i = 0; done = false; while ( !done ) { if ( ns[i].Active == false ) { ns[i] = new Node(i, xi + dir.x, yi + dir.y, size, theta, noiseoff, dir, true, false, true); done = true; if (i == nodeCount - 1 ) { done = true; } } i++; if (i == nodeCount ) { done = true; } } } // Node class class Node { int index; float xi, yi, size, theta, noiseoff; PVector dir; Boolean Active, Growth, Init; Node(int ind, float x, float y, float s, float t, float n, PVector d, Boolean A, Boolean G, Boolean I) { index = ind; xi = x; yi = y; size = s; theta = t; noiseoff = n; dir = d; Active = A; Growth = G; Init = I; } void display(){ // Draw node as two circles and a line strokeWeight(0); ellipse(xi, yi, size, size); ellipse(xi + dir.x, yi + dir.y, size, size); strokeWeight(size); line(xi, yi, xi + dir.x, yi + dir.y); } // Grow method void grow(){ int i = index + 1; PVector tempDir = dir; // Small chance of angle deviation if( random(100) > 85 ){ noiseoff += 0.01; theta = map(noise(noiseoff), 0, 1, -PI/12, PI/12); tempDir.rotate(theta); } // Create new node appended onto the last createNode(xi + tempDir.x, yi + tempDir.y, size, theta, noiseoff, tempDir, true, false, true); // Set growth to false to prevent this node growning again Growth = false; } // Initialize previously grown nodes for growth void init(){ Growth = true; Init = false; } }
Turns out it was my generation of a temporary vector tempDir to rotate (as the .rotate() method rotates the vector and changes it) was slightly incorrect. changing PVector tempDir = dir; to PVector tempDir = new PVector(dir.x, dir.y); Fixed my bug, I guess that somehow the data assignment is getting confused?
Your Node#grow() function loops through every index in the array, replacing each Node with a rotated version of itself. This doesn't make a ton of sense, because you're already looping through every Node and calling the grow() function. So for every Node, you're looping through every Node and replacing it with a rotated version... why? It looks like you're mixing logic that's supposed to operate on every Node with logic that operates on a single Node. Here's a general rule of thumb: your Node class should only ever deal with a single Node, so if you're accessing the ns array, something fishy is going on. (Unless you need each Node to interact with every other Node, but that doesn't seem to be the case here.) To fix your problem, you have to separate the logic that loops through every Node from the logic that modifies a single Node. It might be easier if you start out with a single Node. Get that single Node working before you worry about multiple Node instances. Edit: You're still modifying the array that holds the Node instances from inside every Node. That's the source of your confusion. I see now that you fixed your problem, but I would bet you're going to have similar issues as you continue. Here's the example I was working on. This uses a child variable in each Node instance instead of trying to store the children in the same array that the parent Node instances are stored in. Maybe it'll come in handy: ArrayList<Node> nodes = new ArrayList<Node>(); void setup() { size(500, 500); for(int i = 0; i < 100; i++){ nodes.add(new Node()); } } void mousePressed() { for ( Node node : nodes ) { node.grow(); } } void draw() { background(255); for ( Node node : nodes ) { node.display(); } } class Node { float x; float y; float angle; float length; Node child; Node() { x = random(width); y = random(height); angle = random(360); length = random(5, 10); } void display() { float endX = x + cos(radians(angle)) * length; float endY = y + sin(radians(angle)) * length; line(x, y, endX, endY); if (child != null) { child.display(); } } void grow() { if (child == null) { float endX = x + cos(radians(angle)) * length; float endY = y + sin(radians(angle)) * length; child = new Node(); child.x = endX; child.y = endY; child.angle = random(angle-10, angle+10); } else { child.grow(); } } }