Related
I implemented the improved Perlin noise algorithm. The code as provided for 3D noise works correctly.
I adjusted the algorithm to make a 2D version in what seemed the obvious way. It almost works, but produces artefacts as the images below show.
Here is the correct 3D version:
unsigned inc (unsigned number)
{
return (number + 1) & 255;
}
double fade (double t)
{
// Fade function as defined by Ken Perlin.
// This eases coordinate values
// so that they will "ease" towards integral values.
// This ends up smoothing the final output.
// 6t^5 - 15t^4 + 10t^3
return t * t * t * (t * (t * 6 - 15) + 10);
}
double lerp (double a, double b, double x)
{
return a + x * (b - a);
}
double grad (unsigned hash, double x, double y, double z)
{
// Take the hashed value and take the first 4 bits of it
// (15 == 0b1111)
unsigned h = hash & 15;
// If the most significant bit (MSB) of the hash is 0
// then set u = x. Otherwise y.
double u = h < 8 /* 0b1000 */ ? x : y;
double v;
if (h < 4 /* 0b0100 */)
// If the first and second significant bits
// are 0, set v = y
v = y;
else if (h == 12 /* 0b1100 */ || h == 14 /* 0b1110*/)
// If the first and second significant bits
// are 1, set v = x
v = x;
else
// If the first and second significant bits are not
// equal (0/1, 1/0) set v = z
v = z;
// Use the last 2 bits to decide if u and v are positive
// or negative. Then return their addition.
return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
}
double
ImprovedNoise :: noise (double x, double y, double z)
{
// Calculate the "unit cube" that the point asked will be located in
// The left bound is ( |_x_|,|_y_|,|_z_| ) and the right bound is that
// plus 1. Next we calculate the location (from 0.0 to 1.0) in that
// cube. We also fade the location to smooth the result.
int xi = (int)x & 255;
int yi = (int)y & 255;
int zi = (int)z & 255;
double xf = x - (int) x;
double yf = y - (int) y;
double zf = z - (int) z;
double u = fade (xf);
double v = fade (yf);
double w = fade (zf);
int aaa, aba, aab, abb, baa, bba, bab, bbb;
auto & p = permutation;
aaa = p[p[p[ xi ] + yi ] + zi ];
aba = p[p[p[ xi ] + inc(yi)] + zi ];
aab = p[p[p[ xi ] + yi ] + inc(zi)];
abb = p[p[p[ xi ] + inc(yi)] + inc(zi)];
baa = p[p[p[inc(xi)] + yi ] + zi ];
bba = p[p[p[inc(xi)] + inc(yi)] + zi ];
bab = p[p[p[inc(xi)] + yi ] + inc(zi)];
bbb = p[p[p[inc(xi)] + inc(yi)] + inc(zi)];
double x1, x2, y1, y2;
// The gradient function calculates the dot product between a
// pseudorandom gradient vector and the vector from the input
// coordinate to the 8 surrounding points in its unit cube.
// This is all then lerped together as a sort of weighted average
// based on the faded (u,v,w) values we made earlier.
x1 = lerp (
grad (aaa, xf , yf , zf),
grad (baa, xf-1, yf , zf),
u);
x2 = lerp (
grad (aba, xf , yf-1, zf),
grad (bba, xf-1, yf-1, zf),
u);
y1 = lerp (x1, x2, v);
x1 = lerp (
grad (aab, xf , yf , zf-1),
grad (bab, xf-1, yf , zf-1),
u);
x2 = lerp (
grad (abb, xf , yf-1, zf-1),
grad (bbb, xf-1, yf-1, zf-1),
u);
y2 = lerp (x1, x2, v);
auto result = (lerp (y1, y2, w) + 1) / 2;
assert (0 <= result);
assert (result <= 1);
assert (false == std :: isnan (result));
return result;
}
I generate a 2D image by fixing z=0. This a frequency of 10 so x,y are in [0..10]:
My 2D version:
double grad (unsigned hash, double x, double y)
{
double u = (hash & 1) ? x : y;
double v = (hash & 2) ? x : y;
return ((hash & 4) ? u : -u) + (hash & 8) ? v : -v;
}
double
ImprovedNoise :: noise (double x, double y)
{
int xi = (int)x & 255;
int yi = (int)y & 255;
double xf = x - (int) x;
double yf = y - (int) y;
double u = fade (xf);
double v = fade (yf);
int aaa, aba,baa, bba;
auto & p = permutation;
aaa = p[p[ xi ] + yi ];
aba = p[p[ xi ] + inc(yi)];
baa = p[p[inc(xi)] + yi ];
bba = p[p[inc(xi)] + inc(yi)];
double x1, x2;
// The gradient function calculates the dot product between a
// pseudorandom gradient vector and the vector from the input
// coordinate to the 8 surrounding points in its unit cube.
// This is all then lerped together as a sort of weighted average
// based on the faded (u,v,w) values we made earlier.
x1 = lerp (
grad (aaa, xf , yf),
grad (baa, xf-1, yf),
u);
x2 = lerp (
grad (aba, xf , yf-1),
grad (bba, xf-1, yf-1),
u);
double result = (lerp (x1, x2, v) + 1) / 2;
assert (0 <= result);
assert (result <= 1);
assert (false == std :: isnan (result));
return result;
}
Here is the image it generates.
It's generated using this method:
int size=400;
int freq=10;
create_widget (size, size, [&] (int x, int y)
{
return noise (x*freq / float (size), y*freq / float (size));
});
What's causing those horizontal and vertical lines? I thought it might be an integer boundary issue, but that would predict freq artefacts across the whole image, so I guess it's something else.
Can you see what the mistake is?
There's probably a mistake in grad (the precedence of + is higher than ?:), which causes abrupt change of the (anyway incorrect) result on specific xf/yf/hash values.
return ((hash & 4) ? u : -u) + (hash & 8) ? v : -v;
( )
I have tried a cpp codeblock:
bool comp(const pair<int,int>&A, const pair<int,int>&B)
{
if(A.second<=B.second)
{
if(A.first>=B.first)
return 1;
else
return 0;
}
return 0;
}
int main()
{
int a, b, c, x[10], y[10];
cin>>a;
cin>>b;
cin>>c;
for(int i=0;i<4;++i)
{
cin>>x[i];
y[i]=a*x[i]*x[i]+b*x[i]+c;
}
vector<pair<int,int> >V;
for(int i=0;i<4;++i)
{
V.pb(mp(x[i],y[i]));
}
for(int i=0;i<4;++i)
{
sort(V.begin(),V.end(),&comp);
}
for(int i=0;i<V.size();i++)
{
cout<<V[i].first;
cout<<" "<<V[i].second<<" ";
}
return 0;
}
STDIN: a b c x1 x2 x3... and x is in sorted order i.e. x1 < x2 < x3. The Code should generate a new list (y = y1 y2 y3) using the parabola equation for every x and sort the above list with a run-time complexity of <= O(log n).
STDOUT: x3,y3 x1,y1 x2,y2 ... (assuming computed y3 < y1 < y2.. ).
Code should NOT compute the Y's. Multiplication on this compute node is "too" costly. The solution should identify a way of still sorting the list without computing the "y" values.
My code computes the y values. Can anyone find a method of sorting without computing the y values. A python code implementation would also work for me.
The farther an x value is from the parabola's apex x0, the higher is its y value when a is positive and the lower its y value when a is negative.
|x1 - x0| > |x2 - x0| && a > 0 --> y1 > y2
|x1 - x0| > |x2 - x0| && a < 0 --> y1 < y2
When a is zero, your parabola is really a line and the x values are already sorted in the correct order when b is positive or in the reverse order when b is negative.
So when a isn't zero, find the apex:
x0 = - b / (2*a)
Now find the value in your sorted list of x values that is closest to x:
i = index(x: min(|x - x0|))
Add point i to the list. Create two indices:
l = i - 1
r = i + 1
Now take the point at either index l or r that is closer to the apex, and add it to the list. Update the index until you have exhausted the list.
Revert the list when a is negative. (Or add the items from the end of the list.)
Edit: Here's an implementation in Python. It pops elements off sub-lists rather than using array indices, but the logic is the same:
import bisect
def parasort(a, b, c, x):
"""Return list sorted by y = a*x*x + b*x + c for sorted input x."""
if not x:
return x
if a == 0: # degenerate case: line
if b < 0: return x[::-1]
return x[:]
x0 = -0.5 * b / a # apex of parabola
i = bisect.bisect_left(x, x0) + 1 # closest point via bin. search
l = x[:i][::-1] # left array, reverted
r = x[i:] # right array
res = []
while l and r: # merge l and r
if x0 - l[0] > r[0] - x0: # right item is smaller
res += [r.pop(0)]
else: # left item is smaller
res += [l.pop(0)]
res += l + r # append rest of arrays
if a < 0: return res[::-1]
return res
a = 4
b = 0
c = 0
xx = parasort(a, b, c, [-3, 0, 1, 2])
for x in xx:
print x, a*x*x + b*x + c
I am pretty new to Mathematica. I need to create 2d array dynamicly. I got some code in C++(Qt) and it looks like this:
void Wave::getMatrix(int M, int N)
{
int k = -N;
while(k < N+1){
QVector<tsk_type> temp_vec;
for(int i = -N; i < N+1; i++){
tsk_type temp_sum0;
for(int ii = -M; ii < M+1; ii++ ){
temp_sum0 += (getI(i-ii, b)/getY(ii)) * getJ(ii-k,b1,b2);
}
temp_vec[temp_vec.size()-1] = temp_sum0;
if (k == i)
temp_vec[temp_vec.size()-1] -= l;
}
temp_vec.push_back(getD(S)*getI(S-k, b));
main_array.push_back(temp_vec);
k++;
}
}
/
In Mathematica, I have already written all the functions that I need to make some linear equation system matrix which I can solve. So I use 'em to get 'list' of 'lists'.
When I run this code it's like executing something but outputs nothing. No even errors.
Whats wrong? And how properly I should translate it? also, I assume that there are problem with 'List[]' and 'List[[]]' variables, so how shold I properly declare dynamic lists?
Here is the formula
Heres how I translated the code.
(*all globlas definiton is somewhere here*)
k = -Nm;
mainmatrix = List[[]];
While[k < Nm + 1,
rowvalues = List[];
For[i = -Nm, i < Nm + 1, i++,
tempsum;
For[j = -M, j < M + 1, j++,
tempsum = tempsum + (getI[i - j, a, b]/getGamma[j]) * getJ[j - k, a1, b1, a2, b]
]
AppendTo[rowvalues, tempsum];
If[k == i, AppendTo[rowvalues, -l], 0]
];
AppendTo[rowvalues, getD[S]*getI[S - k, a, b]];
AppendTo[mainmatrix, rowvalues];
k++]
UPD:
all functions and data
Clear[k, a, b, a1, b1, a2, b2, angle, rho, omega, lambda, u];
(*constants*)
rho = 1800; angle = 0.5; lambda = 3 * 10^9; omega = 1.5 * 10^6; u =
2*10^9;
BS = 1; DS = 1; T = 0.01; l = 0.01; S = 0;
a = 0.002; b = 0.008; a1 = 0.0; b1 = 0.002; a2 = 0.008; b2 = 1.0; M =
7; Nm = 7;
getI[k_ , a_, b_] = Integrate[E^(I ((2 Pi)/l) k t), {t, a, b}]
getJ[k_ , a1_, b1_, a2_, b2_] = getI[k, a1, b1] + getI[k, a2, b2]
getL[n_] = angle + (2 Pi n/l);
getK[j_] = If[j == 1,
answer = Sqrt[(rho*omega^2)/(lambda + 2*u)],
answer = Sqrt[(rho*omega^2)/(u)]
]; answer
getBeta[j_, n_] = If[(getL[n] > getK[j]),
beta = 0 + i*(getL[n]* getL[n] * getK[j]*getK[j]),
beta = (getL[n]* getL[n] * getK[j]*getK[j]) + i*0]; beta
getGamma[n_] = (((getL[n]*getL[n])/(getBeta[1, n])) + getBeta[2, n]);
getD[s_] = ((2 getL[s] * BS * getBeta[1, s] + DS) / (getL[s] * getL[s]
+ getBeta[1, s]*getBeta[2, s] ));
I don't know if all this is exactly correct, but it is much closer.
In[1]:= n = 2; M = 2; (*dummy values for this example code*)
getGamma[i_] := RandomReal[]; (* dummy functions for this example code*)
getI[i_, a_, b_] := RandomReal[];
getJ[j_, a1_, b1_, a2_, b_] := RandomReal[];
getD[S_] := RandomReal[];
k = -n;(*N is a predefined Mathematica function and can't be a variable name*)
mainmatrix = List[];
While[k < n+1,
rowvalues = List[];
For[i = -n, i < n+1, i++,
AppendTo[rowvalues, getGamma[i]];
tempsum = 0; (*I think you wanted this initialized here*)
For[j = -M, j < M+1, j++,
tempsum += getI[i-j, a, b]/getGamma[j]*getJ[j-k, a1, b1, a2, b]
];
AppendTo[rowvalues, tempsum];
If[k == i, AppendTo[rowvalues, -l]] (*no "else" needed if else does nothing*)
];
AppendTo[rowvalues, getD[S]*getI[S-k, a, b]];
AppendTo[mainmatrix, rowvalues];
k++
];
mainmatrix (*display result*)
Out[8]= {{0.135926, 0.894736, -l, 0.699663, 1.91913, 0.702762,
28.4151, 0.730135, 19.6996, 0.583233, 21.2716, 0.398302},
{0.572982, 3.18868, 0.495877, 1.50816, -l, 0.686158,
68.9278, 0.860748, 3.91516, 0.751198, 8.43028, 0.223722},
{0.931385, 3.16432, 0.931398, 5.10999, 0.241402, 4.54042,
-l, 0.825971, 2.99634, 0.280342, 3.20253, 0.0731139},
{0.294396, 7.99678, 0.456691, 4.74995, 0.308643, 1.72647,
0.883139, 5.64323, -l, 0.755833, 4.00285, 0.127718},
{0.790168, 0.751702, 0.744966, 2.40172, 0.537242, 3.08838,
0.105972, 1.09212, 0.412047, 12.2475, -l, 0.397379}}
When time comes to use the matrix result realize that all Mathematica matrix and vector subscripts are 1..n, not 0..n-1 and not -n..n. So you will have to add an offset to any matrix subscripts when modifying code to use the resulting matrix.
You could, if it mattered to you, replace
tempsum = 0;(*I think you wanted this initialized here*)
For[j = -M, j < M + 1, j++,
tempsum += getI[i - j, a, b]/getGamma[j]*getJ[j - k, a1, b1, a2, b]];
AppendTo[rowvalues, tempsum];
with
AppendTo[rowvalues,Sum[getI[i-j,a,b]/getGamma[j]*getJ[j-k,a1,b1,a2,b],{j,-M,M}]];
That might have, for example, avoided the original bug of not initializing tempsum.
There are other bits of the code that could be rewritten to make use of Mathematica features, but you have to decide whether this would be good or bad to do.
here you go without all the nasty use of AppendTo
mainmatrix = Table[
Insert[
Append[
Flatten#Table[ {
getGamma[i],
Sum[getI[i - j, a, b]/getGamma[j] getJ[j - k, a1, b1, a2, b],
{j, -M, M}] },
{i, -n, n}] ,
getD[S]*getI[S - k, a, b]],
-l,2 (k + n + 1) + 1 ],
{k, -n, n}];
Edit:
on further study, it appears the C++ code actually throws away the getY(i) value it pushes onto temp_vec, the result is even simpler:
mainmatrix = Table[
Append[
Table[ Sum[getI[i - j, a, b]/
getGamma[j] getJ[j - k, a1, b1, a2, b]-l Boole[i == k],
{j, -M, M}] , {i, -n, n}] ,
getD[S]*getI[S - k, a, b]], {k, -n, n}];
yet another form, which actually begins to resemble your equation..
lhs = Table[Sum[getI[i - j, a, b]/
getGamma[j] getJ[j - k, a1, b1, a2, b], {j, -M, M}],
{k, -n, n}, {i, -n, n}] - l IdentityMatrix[2 n + 1];
rhs = Table[ getD[S]*getI[S - k, a, b] , {k, -n, n}];
mainmatrix= Join[lhs, Transpose[{rhs}], 2]
In opencv and C++, if I have previously found a transformation matrix between 2 images, why do I need to do this
Mat affineTransform=getAffineTransform(coordinates_1.data(),coordinates_2.data()) ;
Mat perspectiveTransform=Mat::eye(3,3,CV_64FC1);
for(unsigned int y=0; y<2; ++y){
for(unsigned int x=0; x<3; ++x){
perspectiveTransform.at<double>(y,x) = affineTransform.at<double>(y,x);
}
instead of applying the transformation matrix to an image directly. I understand the meaning of Mat::eye() but why go through all this?
Note: originalTranformationMatrix is a Mat object and the found transformation matrix is a 3 x 3 matrix
Affine transform has following form:
(a, b, c)
(d, e, f)
It transform point (x,y) in following way:
x_new = a*x + b*y + c;
y_new = d*x + e*y + f;
Perspective transform has following form:
(a, b, c)
(d, e, f)
(g, h, 1)
It transform point (x,y) in following way:
z = g*x + h*y + 1;
x_new = (a*x + b*y + c)/z;
y_new = (d*x + e*y + f)/z;
That means that if you want to define perspective transform that does only affine transformation, it should be:
(a, b, c)
(d, e, f)
(0, 0, 1)
And this is exactly what your code does. First it creates matrix:
(1, 0, 0)
(0, 1, 0)
(0, 0, 1)
And than replaces first two rows with rows of affine transformation. By the way, it can be done in cleaner way without loops:
perspectiveTransform(Rect(0,0,3,2)) = affineTransform.clone();
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
So this RT code creates a 3D image, with blur, through raw code. How is that actually done without any modelling tools?
I am currently working to understand how RT work and different ways to implement them, so this was kind of cool to see such a small amount of code producing a pretty impressive 3D image.
#include <stdlib.h> // card > aek.ppm
#include <stdio.h>
#include <math.h>
#include <fstream>
typedef int i;
typedef float f;
struct v {
f x, y, z;
v operator+(v r) {
return v(x + r.x, y + r.y, z + r.z);
}
v operator*(f r) {
return v(x * r, y * r, z * r);
}
f operator%(v r) {
return x * r.x + y * r.y + z * r.z;
}
v() {}
v operator^(v r) {
return v(y * r.z - z * r.y, z * r.x - x * r.z, x * r.y - y * r.x);
}
v(f a, f b, f c) {x = a; y = b; z = c;}
v operator!() {
return*this * (1 / sqrt(*this % *this));
}
};
i G[] = {247570, 280596, 280600, 249748, 18578, 18577, 231184, 16, 16};
f R()
{
return(f)rand() / RAND_MAX;
}
i T(v o, v d, f&t, v&n)
{
t = 1e9; i m = 0;
f p = -o.z / d.z;
if(.01 < p)t = p, n = v(0, 0, 1), m = 1;
for(i k = 19; k--;)
for(i j = 9; j--;)if(G[j] & 1 << k) {
v p = o + v(-k, 0, -j - 4);
f b = p % d, c = p % p - 1, q = b * b - c;
if(q > 0) {
f s = -b - sqrt(q);
if(s < t && s > .01)
t = s, n = !(p + d * t), m = 2;
}
}
return m;
} v S(v o, v d)
{
f t;
v n;
i m = T(o, d, t, n);
if(!m)return v(.7, .6, 1) * pow(1 - d.z, 4);
v h = o + d * t, l = !(v(9 + R(), 9 + R(), 16) + h * -1), r = d + n * (n % d * -2);
f b = l % n; if(b < 0 || T(h, l, t, n))b = 0;
f p = pow(l % r * (b > 0), 99);
if(m & 1) {
h = h * .2;
return((i)(ceil(h.x) + ceil(h.y)) & 1 ? v(3, 1, 1) : v(3, 3, 3)) * (b * .2 + .1);
} return v(p, p, p) + S(h, r) * .5;
} i
main()
{
FILE * pFile;
pFile = fopen("d:\\myfile3.ppm", "w");
fprintf(pFile,"P6 512 512 255 ");
v g = !v(-6, -16, 0), a = !(v(0, 0, 1) ^ g) * .002, b = !(g ^ a) * .002, c = (a + b) * -256 + g;
for(i y = 512; y--;)
for(i x = 512; x--;) {
v p(13, 13, 13);
for(i r = 64; r--;) {
v t = a * (R() - .5) * 99 + b * (R() - .5) * 99;
p = S(v(17, 16, 8) + t, !(t * -1 + (a * (R() + x) + b * (y + R()) + c) * 16)) * 3.5 + p;
}
fprintf(pFile, "%c%c%c", (i)p.x, (i)p.y, (i)p.z);
}
}
My dear friend that's Paul Heckbert code's right?
You could at least mention it.
For people thinking this code is unreadable, here is why:
This guy made a code that could fit on a credit card, that was the goal :)
His website: http://www.cs.cmu.edu/~ph/
Edit: Knowing the source of this code may help you understand it. Even if it'snot your main motivation...
If you are really interested in raytracing, start with other sources.
Take a look at this website http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-1-writing-a-simple-raytracer/source-code/ (Plus it talk about your code)
This code is not really special. It is basically a ray tracer that was obfuscated into a form that makes it fit on a business card (see https://www.cs.cmu.edu/~ph/).
How is that actually done without any modelling tools?
You don't need tools to render anything. You could even create a complete game of WoW (or what's hip at the moment) without any modelling tool. Modelling tools just make your live easier w.r.t. certain kinds of scenes (read: very complex ones).
You could always hardcode these data, or hack them manually into some external file.
You could also use parametric generators; Perlin Noise is one of the more popular examples thereof.
In a ray tracer, it happens that it is very simple to start out without modelling tools, as it is very simple to calculate geometric intersections between the rendering primitive "ray" and any finite geometric primitive. E.g., intersection a non-approximated, "perfect" sphere is just a few lines of code.
tl;dr: Data is just data. How you create and crunch it is completely up to you.