Triangle rasterizer using change of basis - algorithm

My triangle rasterization program works as-is, but I would like to make it easier to use by specifying explicit coordinates instead of differentials. Unfortunately, I don't know how to calculate the necessary change-of-basis matrix. This can be seen by the empty "rasterizeCnvTri" function.
The following section is my code, using the PixelToaster library for a framebuffer:
// TrueColor Example
// How to open a display in truecolor mode and work with 32 bit integer pixels.
// Copyright © Glenn Fiedler, 2004-2005. http://www.pixeltoaster.com
#include "pt/source/PixelToaster.h"
using namespace PixelToaster;
int fbuf[256][256][3];
int zbuf[256][256];
void rasterizeTriangle(int u,int dudx,int dudy,int v,int dvdx,int dvdy,int w,int dwdx,int dwdy,int r,int g,int b)
{
int u_rw = u;
int v_rw = v;
int w_rw = w;
for(int j=0; j<256; j++)
{
int u_pt = u_rw;
int v_pt = v_rw;
int w_pt = w_rw;
for(int i=0; i<256; i++)
{
if(w_pt>=zbuf[i][j] && u_pt>=0 && v_pt>=0 && (u_pt+v_pt)<4096)
{fbuf[i][j][0]=r; fbuf[i][j][1]=g; fbuf[i][j][2]=b; zbuf[i][j]=w_pt;}
u_pt += dudx;
v_pt += dvdx;
w_pt += dwdx;
}
u_rw += dudy;
v_rw += dvdy;
w_rw += dwdy;
}
}
void rasterizeCnvTri(int x1,int x2,int x3,int y1,int y2,int y3,int w1,int w2,int w3,int r,int g,int b)
{
//how to do this?
}
int main()
{
const int width = 256;
const int height = 256;
Display display( "Triangle Rasterizer", width, height, Output::Default, Mode::TrueColor );
vector<TrueColorPixel> pixels( width * height );
rasterizeTriangle(-2048,32,0,-2048,0,32,2048,0,0,255,0,0);
rasterizeTriangle(0,32,-32,-2048,0,32,4096,-16,0,255,255,255);
while ( display.open() )
{
unsigned int index = 0;
for ( int y = 0; y < height; ++y )
{
for ( int x = 0; x < width; ++x )
{
pixels[index].r = fbuf[x][y][0];
pixels[index].g = fbuf[x][y][1];
pixels[index].b = fbuf[x][y][2];
++index;
}
}
display.update( pixels );
}
}
U and V are the axes along two of the sides, and W is the inverse depth. All three coordinates are scaled by 4096, so integers are sufficient.
[EDIT]
The following code works for me (also does basic perspective divide):
void rasterizeCnvTri(int x1,int x2,int x3,int y1,int y2,int y3,int w1,int w2,int w3,int r,int g,int b)
{
int xp1 = (((x1-128)*w1)>>8)+128;
int yp1 = (((y1-128)*w1)>>8)+128;
int xp2 = (((x2-128)*w2)>>8)+128;
int yp2 = (((y2-128)*w2)>>8)+128;
int xp3 = (((x3-128)*w3)>>8)+128;
int yp3 = (((y3-128)*w3)>>8)+128;
int xd2 = xp2-xp1;
int xd3 = xp3-xp1;
int yd2 = yp2-yp1;
int yd3 = yp3-yp1;
int wd2 = w2-w1;
int wd3 = w3-w1;
int plna = (yd2*wd3)-(yd3*wd2);
int plnb = (wd2*xd3)-(wd3*xd2);
int plnc = (xd2*yd3)-(xd3*yd2);
int plnd = -(plna*xp1)-(plnb*yp1)-(plnc*w1);
int invdet = (xd2*yd3)-(yd2*xd3);
int dudx = (-yd3<<12)/invdet;
int dudy = (yd2<<12)/invdet;
int u = (-xp1*dudx)-(yp1*dudy);
int dvdx = (xd3<<12)/invdet;
int dvdy = (-xd2<<12)/invdet;
int v = (-xp1*dvdx)-(yp1*dvdy);
rasterizeTriangle(-u,-dudx,-dudy,-v,-dvdx,-dvdy,-plnd/plnc,-plna/plnc,-plnb/plnc,r,g,b);
}

Related

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?

How to write this processing code in an alternative (beginner) way?

How do I write the code (below) in an alternative (beginner) way? I don't wish to use createShape, setFill and addChild. Instead, any other way to perform the same thing?
grid = createShape(GROUP)
for i in range(C*R):
self.cell = createShape(RECT, (i%C)*S, (i//C)*S, S, S)
self.cell.setFill(colors[i] if i in filled else 210)
grid.addChild(self.cell)
Assuming that you're try to create a rectangle grid:
final int _numRows = 5;
final int _numCols = 7;
int l = 20;
int t = 20;
int w = 90;
int h = 60;
int hg = 10;
int vg = 10;
int left;
int top;
void rectGrid() {
for(int k = 0; k < _numRows; k++) {
for(int j = 0; j < _numCols; j++){
left = l + j*(w+vg);
top = t + k*(h+hg);
stroke(255);
strokeWeight(2);
fill(118);
rect( left, top, w, h);
}
}
}
void setup() {
size(800,500);
background(0,0,245);
rectGrid();
}
void draw() {
}
Adds a color array:
/*
Adds color array to rectangle grid.
*/
final int _numRows = 5;
final int _numCols = 7;
int l = 20;
int t = 20;
int w = 90;
int h = 60;
int hg = 10;
int vg = 10;
int left;
int top;
int count = 0;
color[] c;
void colorArray(){
for(int x=0; x< _numRows*_numCols; x++){
c[x] = color(random(255),random(255),random(255))
}
}
void rectGrid() {
for(int k = 0; k < _numRows; k++) {
for(int j = 0; j < _numCols; j++){
left = l + j*(w+vg);
top = t + k*(h+hg);
stroke(255);
strokeWeight(2);
fill(c[count]);
rect( left, top, w, h);
count++;
}
}
}
void setup() {
size(800,500);
background(0,0,245);
c = new color[_numCols*_numRows];
colorArray();
// Make sure the color array is filled first
rectGrid();
}
void draw() {
}

Kd Tree or Bounding Box Not Working Properly

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);
}
};

How to debug "ArrayIndexOutOfBoundsException: 0" in Processing

I'm trying to make Kim Asendorf's pixel sorting code work with input from a webcam in processing.
I get the error: "ArrayIndexOutOfBoundsException: 0". Any ideas of how I can fix this?
//BLACK
int getFirstNotBlackY(int _x, int _y) {
int x = _x;
int y = _y;
color c;
if (y < height) {
while ( (c = cam.pixels[x + y * cam.width]) < blackValue) {
y++;
if (y >= height) return -1;
}
import processing.video.*;
Capture cam;
String[] cameras = Capture.list();
int mode = 0;
//MODE:
//0 -> black
//1 -> bright
//2 -> white
//b(16777216)
int loops = 1;
int blackValue = -10000000;
int brigthnessValue = 60;
int whiteValue = -6000000;
int row = 0;
int column =
boolean saved = false;
void setup() {
size(640, 480);
import processing.video.*;
String[] cameras = Capture.list();
import processing.video.*;
if (cameras.length == 0) {
println("There are no cameras available for capture.");
exit();
} else {
println("Available cameras:");
for (int i = 0; i < cameras.length; i++) {
println(cameras[i]);
}
// The camera can be initialized directly using an
// element from the array returned by list():
cam = new Capture(this, cameras[0]);
cam.start();
}
}
I've added the code I'm using to initialize the webcam.

xCode 3.2.6. Audio unit programming. IIR filter

My name's Antonio from Italy.
I'm trying to create an Audio Unit using xCode 3.2.6, starting from the example at
this link.
This is my first AU project, and I have no other examples to follow.
My project consists of an IIR notch filter. The algorithm I made works fine (I tested in on Matlab), but the AU doesn't work properly (tested on AU Lab). The .mp3 file sounds filtered, but something like a square wave (I suppose by ear) is overlapped with it.
The frequency of that noise seems to be proportional to the f0 parameter.
Here is the .cpp file code:
// Filtro.cpp
#include "Filtro.h"
#define pi 3.1415926535
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
COMPONENT_ENTRY(Filtro)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Filtro::Filtro
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Filtro::Filtro (AudioUnit component) : AUEffectBase (component) {
CreateElements ();
Globals () -> UseIndexedParameters (kNumberOfParameters);
SetParameter (kParameter_Gain, kDefaultValue_Gain);
SetParameter (kParameter_f0, kDefaultValue_f0);
SetParameter (kParameter_Q, kDefaultValue_Q);
// code for setting default values for the audio unit parameters
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Filtro::GetParameterInfo
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#pragma mark ____Parameters
ComponentResult Filtro::GetParameterInfo (
AudioUnitScope inScope,
AudioUnitParameterID inParameterID,
AudioUnitParameterInfo &outParameterInfo
) {
ComponentResult result = noErr;
outParameterInfo.flags = kAudioUnitParameterFlag_IsWritable
| kAudioUnitParameterFlag_IsReadable;
if (inScope == kAudioUnitScope_Global) {
switch (inParameterID) {
case kParameter_Gain:
AUBase::FillInParameterName (
outParameterInfo,
kParamName_Gain,
false
);
outParameterInfo.unit = kAudioUnitParameterUnit_Decibels;
outParameterInfo.minValue = kMinimumValue_Gain;
outParameterInfo.maxValue = kMaximumValue_Gain;
outParameterInfo.defaultValue = kDefaultValue_Gain;
break;
case kParameter_f0: // 9
AUBase::FillInParameterName (
outParameterInfo,
kParamName_f0,
false
);
outParameterInfo.unit = kAudioUnitParameterUnit_Hertz;
outParameterInfo.minValue = kMinimumValue_f0;
outParameterInfo.maxValue = kMaximumValue_f0;
outParameterInfo.defaultValue = kDefaultValue_f0;
outParameterInfo.flags |= kAudioUnitParameterFlag_DisplayLogarithmic;
break;
case kParameter_Q: // 9
AUBase::FillInParameterName (
outParameterInfo,
kParamName_Q,
false
);
outParameterInfo.unit = kAudioUnitParameterUnit_Generic;
outParameterInfo.minValue = kMinimumValue_Q;
outParameterInfo.maxValue = kMaximumValue_Q;
outParameterInfo.defaultValue = kDefaultValue_Q;
outParameterInfo.flags |= kAudioUnitParameterFlag_DisplayLogarithmic;
break;
default:
result = kAudioUnitErr_InvalidParameter;
break;
}
} else {
result = kAudioUnitErr_InvalidParameter;
}
return result;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Filtro::GetPropertyInfo
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSStatus Filtro::GetPropertyInfo ( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 &outDataSize,
Boolean &outWritable)
{
return AUEffectBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Filtro::GetProperty
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSStatus Filtro::GetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void *outData )
{
return AUEffectBase::GetProperty (inID, inScope, inElement, outData);
}
#pragma mark ____FiltroEffectKernel
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Filtro::FiltroKernel::FiltroKernel()
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Filtro::FiltroKernel::FiltroKernel (AUEffectBase *inAudioUnit) :
AUKernelBase (inAudioUnit), mSamplesProcessed (0), mCurrentScale (0) // 1
{
mSampleFrequency = GetSampleRate ();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Filtro::FiltroKernel::Reset()
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Filtro::FiltroKernel::Reset() {
mCurrentScale = 0;
mSamplesProcessed = 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Filtro::FiltroKernel::Process
void Filtro::FiltroKernel::Process (const Float32 *inSourceP,
Float32 *inDestP,
UInt32 inSamplesToProcess,
UInt32 inNumChannels,
bool &ioSilence
) {
if (!ioSilence) {
const Float32 *sourceP = inSourceP;
Float32 *destP = inDestP, inputSample, outputSample;
Float32 Fs= mSampleFrequency;
int f0;
float w0, alpha, b0, b1, b2, a0, a1, a2;
float gain, dBgain, Q, coeff[5], x[5]={0,0,0,0,0} , out = 0;
dBgain = GetParameter (kParameter_Gain); //Get parameter from interface
if (dBgain < kMinimumValue_Gain) dBgain = kMinimumValue_Gain; //Check the right range
if (dBgain > kMaximumValue_Gain) dBgain = kMaximumValue_Gain;
f0 = GetParameter (kParameter_f0);
if (f0 < kMinimumValue_f0) f0 = kMinimumValue_f0;
if (f0 > kMaximumValue_f0) f0 = kMaximumValue_f0;
Q = GetParameter (kParameter_Q);
if (Q < kMinimumValue_Q) Q = kMinimumValue_Q;
if (Q > kMaximumValue_Q) Q = kMaximumValue_Q;
w0 = 2*pi*f0/Fs;
alpha = sin(w0)*sinh(log(2)/(log(exp(1))*2) * Q * w0/sin(w0));
b0 = 1;
b1 = -2*cos(w0);
b2 = 1;
a0 = 1 + alpha;
a1 = -2*cos(w0);
a2 = 1 - alpha;
coeff[0] = b0/a0;
coeff[1] = b1/a0;
coeff[2] = b2/a0;
coeff[3] = -a1/a0;
coeff[4] = -a2/a0;
//----------------------------------------------------------------------------------------------//
// y(n) = b0/a0 * x(n) + b1/a0 * x(n-1) + b2/a0 * x(n-2) * -a1/a0 * y(n-1) * -a2/a0 * y(n-2) //
//----------------------------------------------------------------------------------------------//
for (int i = inSamplesToProcess; i > 0; --i) {
int index = static_cast<long>(mSamplesProcessed * mCurrentScale) % 512; //?
if ((mNextScale != mCurrentScale) && (index == 0)) { //??
mCurrentScale = mNextScale;
mSamplesProcessed = 0;
}
if ((mSamplesProcessed >= sampleLimit) && (index == 0)) { // ??
mSamplesProcessed = 0;
}
gain = pow(10, dBgain/20);
inputSample = *sourceP;
x[0] = inputSample; //x(n)
x[3] = outputSample; //y(n-1)
for (int h = 0; h < 5; h++) { // Processing output sample
out = out+x[h]*coeff[h];
}
for (int h = 4; h > 0; h--) {
x[h]=x[h-1]; //I/O array shifting
}
outputSample = out * gain;
out = 0;
*destP = outputSample;
sourceP += 1;
destP += 1;
mSamplesProcessed += 1;
}
}
}
And that's the header file:
// Filtro.h
#include "AUEffectBase.h"
#include "AUEffectBase.h"
#include "FiltroVersion.h"
#if AU_DEBUG_DISPATCHER
#include "AUDebugDispatcher.h"
#endif
#ifndef __Filtro_h__
#define __Filtro_h__
#pragma mark ____Filtro Parameter Constants
static CFStringRef kParamName_Gain = CFSTR ("Gain");
static const double kDefaultValue_Gain = 0;
static const double kMinimumValue_Gain = -40;
static const double kMaximumValue_Gain = 0;
static CFStringRef kParamName_f0 = CFSTR ("f0");
static const int kDefaultValue_f0 = 1048;
static const int kMinimumValue_f0 = 50;
static const int kMaximumValue_f0 = 20000;
static CFStringRef kParamName_Q = CFSTR ("Q");
static const double kDefaultValue_Q = 0.1;
static const double kMinimumValue_Q = 0.001;
static const double kMaximumValue_Q = 10;
// parameter identifiers
enum { // Defines constants for identifying the parameters; defines the total number of parameters
kParameter_Gain = 0,
kParameter_f0 = 1,
kParameter_Q = 2,
kNumberOfParameters = 3
};
#pragma mark ____Filtro
class Filtro : public AUEffectBase
{
public:
Filtro(AudioUnit component);
#if AU_DEBUG_DISPATCHER
virtual ~Filtro () { delete mDebugDispatcher; }
#endif
virtual AUKernelBase * NewKernel() { return new FiltroKernel(this); }
virtual OSStatus GetParameterInfo(AudioUnitScope inScope,
AudioUnitParameterID inParameterID,
AudioUnitParameterInfo &outParameterInfo);
virtual OSStatus GetPropertyInfo(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 & outDataSize,
Boolean & outWritable );
virtual OSStatus GetProperty(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData);
virtual bool SupportsTail () { return false; } // FIND
/*! #method Version */
virtual OSStatus Version() { return kFiltroVersion; }
// virtual ComponentResult GetPresets (CFArrayRef *outData) const;
// virtual OSStatus NewFactoryPresetSet (const AUPreset &inNewFactoryPreset);
protected:
class FiltroKernel : public AUKernelBase {
public:
FiltroKernel (AUEffectBase *inAudioUnit); // 1
virtual void Process (
const Float32 *inSourceP,
Float32 *inDestP,
UInt32 inFramesToProcess,
UInt32 inNumChannels, // equal to 1
bool &ioSilence
);
virtual void Reset();
private:
Float32 mSampleFrequency;
long mSamplesProcessed;
enum {sampleLimit = (int) 10E6};
float mCurrentScale;
float mNextScale;
};
};
#endif#include "FiltroVersion.h"
#if AU_DEBUG_DISPATCHER
#include "AUDebugDispatcher.h"
#endif
#ifndef __Filtro_h__
#define __Filtro_h__
#pragma mark ____Filtro Parameter Constants
static CFStringRef kParamName_Gain = CFSTR ("Gain");
static const double kDefaultValue_Gain = 0;
static const double kMinimumValue_Gain = -40;
static const double kMaximumValue_Gain = 0;
static CFStringRef kParamName_f0 = CFSTR ("f0");
static const int kDefaultValue_f0 = 1048;
static const int kMinimumValue_f0 = 50;
static const int kMaximumValue_f0 = 20000;
static CFStringRef kParamName_Q = CFSTR ("Q");
static const double kDefaultValue_Q = 0.1;
static const double kMinimumValue_Q = 0.001;
static const double kMaximumValue_Q = 10;
// parameter identifiers
enum { // Defines constants for identifying the parameters; defines the total number of parameters
kParameter_Gain = 0,
kParameter_f0 = 1,
kParameter_Q = 2,
kNumberOfParameters = 3
};
#pragma mark ____Filtro
class Filtro : public AUEffectBase
{
public:
Filtro(AudioUnit component);
#if AU_DEBUG_DISPATCHER
virtual ~Filtro () { delete mDebugDispatcher; }
#endif
virtual AUKernelBase * NewKernel() { return new FiltroKernel(this); }
virtual OSStatus GetParameterInfo(AudioUnitScope inScope,
AudioUnitParameterID inParameterID,
AudioUnitParameterInfo &outParameterInfo);
virtual OSStatus GetPropertyInfo(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 & outDataSize,
Boolean & outWritable );
virtual OSStatus GetProperty(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData);
virtual bool SupportsTail () { return false; }
/*! #method Version */
virtual OSStatus Version() { return kFiltroVersion; }
protected:
class FiltroKernel : public AUKernelBase {
public:
FiltroKernel (AUEffectBase *inAudioUnit);
virtual void Process (
const Float32 *inSourceP,
Float32 *inDestP,
UInt32 inFramesToProcess,
UInt32 inNumChannels, // equal to 1
bool &ioSilence
);
virtual void Reset();
private:
Float32 mSampleFrequency;
long mSamplesProcessed;
enum {sampleLimit = (int) 10E6};
float mCurrentScale;
float mNextScale;
};
};
#endif
Thank a lot. I hope my English is not too bad.
Your filter implementation does not look correct to me. Maybe it's fine, but it's hard to follow. For example, it looks like you are shifting your stored x values into your stored y values, and even though you clear that up on the next loop, it's all a bit hard to follow.
You might want to check out how I do it here: http://blog.bjornroche.com/2012/08/basic-audio-eqs.html Much cleaner!
Also, are you processing mono samples or multichannel audio, because your Process function looks like it will only work as you intend with mono audio. (I haven't worked with AU's recently enough to be able to answer this myself from looking at your code)
Problem solved!!! After 3 days, I found the right way to avoid the variables reset every audio frame. I just declared those state variables into the Filtro.h file at the fourth line from the bottom, and than I initialised them into the "AUKernelBase (inAudioUnit)" in Filtro.cpp file. I hope it can be helpful to other people. Bye.

Resources