Thanks guys.
Request for help
Can someone who has a good understanding of 3D vectors please run over this code? It's producing... "weird" artifacts to say the least:
http://www.imgwiz.com/images/2013/06/05/R65C3.png
It's very well commented, and should be self explanatory.
All I need to know is whether or not I'm calculating the ray correctly (orange line). It has nothing to do with fractals or the 4th dimension, it is simply transforming a screen coordinate into real world space.
Below is an image representing a camera in 3D space. The view frustum of the camera is defined through a 2D screen (ranging from -1,-1 to 1,1), and field of view (fovy). The aspect ratio is 1:1 (square).
eyePosition and
eyeDirection are the camera's position and direction respectively.
Vertex Shader
/* -------------------------------------------------------------
Theory
-------------------------------------------------------------
In order to display a 4D fractal, every "pixel" must be
sliced by a 3D volume, and then projected onto a 2D plane
(the screen).
Iterating 4D-pixels is too inefficient, so they must be
first searched for before running the mandelbrot algorithm.
For every pixel on the screen, a directional vector in 3D
space is calculated by transforming the screen pixel into
3D using the camera's frustum and orientation. The result
is a 3D line (also known as "ray"), which we assume at some
point intersects the 4D fractal we are looking to generate.
The point of intersection is approximated by first stepping
along the ray with evenly distributed step distances until
a point is found, and then is refined through successive
approximation.
In order to test the points along the ray, the 3D point
is transformed into 4-dimensional space through the defined
3D slice volume. Once transformed, the mandelbrot algorithm
can be executed: Z->Z^2 + c, where Z and c are quaternions.
The number of iterations from executing the mandelbrot
algorithm are directly proportional to the final pixel colour.
-------------------------------------------------------------
Math
-------------------------------------------------------------
*** 3D Ray ***
(still figuring this out)
*** 4D slice ***
The volumetric slice in 4D space is defined as:
/tx\ /x1\ /x2\ /x3\
V:R=| ty | + x*| y1 | + y*| y2 | + z*| y3 |
| tz | | z1 | | z2 | | z3 |
\tw/ \w1/ \w2/ \w3/
Where x,y,z represent the resulting slice in 3D space.
Represented as a transformation matrix:
/x1 x2 x3 tx\
| y1 y2 y3 ty |
| z1 z2 z3 tz |
\w1 w2 w3 tw/
-------------------------------------------------------------*/
// -------------------------------------------------------------
// uniforms
// -------------------------------------------------------------
uniform float fovy;
uniform float znear;
uniform float zfar;
uniform vec4 eyePosition;
// -------------------------------------------------------------
// varyings
// -------------------------------------------------------------
varying mat4 mat4DTransform;
// -------------------------------------------------------------
// vertex shader
// -------------------------------------------------------------
void main( void )
{
// snap vertices to edge of screen
vec2 P = sign( gl_Vertex.xy );
// snap UV coordinates to edge of screen
gl_TexCoord[0].xy = P * 0.5 + 0.5;
// calculate the 4D transformation matrix
mat4DTransform = mat4(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 0.0
);
// align object to screen
gl_Position = vec4( P, 0.0, 1.0 );
}
Fragment Shader
// -------------------------------------------------------------
// uniforms
// -------------------------------------------------------------
uniform float znear;
uniform float zfar;
uniform float fovy;
uniform vec4 eyePosition;
uniform vec4 eyeDirection;
uniform float traceMaximumSteps;
uniform float maxIterations;
// -------------------------------------------------------------
// varyings
// -------------------------------------------------------------
varying mat4 mat4DTransform;
// -------------------------------------------------------------
// function prototypes
// -------------------------------------------------------------
float iterate4DPoint( vec4 c );
// -------------------------------------------------------------
// fragment shader
// -------------------------------------------------------------
void main(void)
{
// final colour is stored here
vec4 colour = vec4( 0.0, 0.0, 0.0, 1.0 );
// calculate directional vector of 3D ray
// using the view frustum
// the result is a relative direction of the ray
// to the camera
vec3 rayDirection = normalize( vec3(
tan(gl_TexCoord[0].x*fovy),
tan(gl_TexCoord[0].y*fovy),
1.0
));
// calculate ray direction in global space
// by adding view direction to ray direction
rayDirection = normalize( rayDirection + eyeDirection.xyz );
// calculate vectors representing the screen plane in
// global 3D space
vec3 globalScreenPlaneXDirection = normalize( vec3( eyeDirection.z, 0.0, eyeDirection.x ) );
vec3 globalScreenPlaneYDirection = normalize( cross( eyeDirection.xyz, globalScreenPlaneXDirection ) );
// calculate where the pixel on the screen is
// in global 3D space.
// this position serves as the "r0" vector of the ray,
// and combined with the directional vector of the ray
// describes the ray in 3D.
vec4 rayOffset = vec4( (gl_TexCoord[0].x*globalScreenPlaneXDirection) + (gl_TexCoord[0].y*globalScreenPlaneYDirection), 1.0 );
rayOffset += eyePosition;
// calculate trace step distance
float traceStepDistance = (zfar-znear) / traceMaximumSteps;
// trace linearly along ray until a point inside the fractal
// has been found
for( float currentPos = znear; currentPos < zfar; currentPos+=traceStepDistance )
{
vec4 targetPoint = mat4DTransform * ( rayDirection*currentPos + rayOffset );
// target point has been found
if( targetPoint.x*targetPoint.x + targetPoint.y*targetPoint.y + targetPoint.z*targetPoint.z + targetPoint.w*targetPoint.w < 4.0 )
{
// plug 4-dimensional point as entering condition
// into mandelbrot formula Z-->Z^2 + c
//float iterations = iterate4DPoint( targetPoint );
colour = vec4( 1.0, 1.0, 0.0, 1.0 );
}
}
gl_FragColor = colour;
}
// runs the mandelbrot algorithm using quaternions
// returns the number of iterations before escape
float iterate4DPoint( vec4 c )
{
// Z component as quaternion
vec4 Z = vec4( 0.0, 0.0, 0.0, 0.0 );
// iterate
float iteration;
for( iteration = 0.0; iteration <= maxIterations; iteration += 1.0 )
{
// raise Z to the power of 2 as quaternion
vec4 temp = Z;
Z.x = (temp.x*temp.x) - (temp.y*temp.y) - (temp.z-temp.z) - (temp.w - temp.w);
Z.y = temp.x*temp.y; Z.y += Z.y; // multiply by 2.0
Z.z = temp.x*temp.z; Z.z += Z.z; // multiply by 2.0
Z.w = temp.x*temp.w; Z.w += Z.w; // multiply by 2.0
// add c
Z += c;
// check for escape condition
if( Z.x*Z.x + Z.y*Z.y + Z.z*Z.z + Z.w*Z.w > 4.0) break;
}
// return number of iterations
return iteration;
}
If it has any significance, the uniforms were set to the following values in the screen shot:
znear = 0.1
zfar = 1.6
fovy = 62 (field of view in degrees)
traceMaximumSteps = 200
maxIterations = 50
eyePosition = camera position
eyeDirection = camera direction (normalized)
Thanks for your time.
TheComet

Yesterday is History, Tomorrow is a Mystery, but Today is a Gift. That is why it is called "present".