I have a code that successfully draws projectiles in 2D, but I need to apply changes to make it in 3D.
#include <stdio.h>
#include <GL/glut.h>
#include <math.h>
#include <unistd.h>
#define g 9.8
#define PI 3.14
#define ESC 27
void initialize(void)
{
glClearColor(0, 0, 0, 0);
glColor3f(0.0, 1.0, 0.0);
glPointSize(3.0);
glEnable(GL_POINT_SMOOTH);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, 1000, 0, 500);
}
static void keyPressFunc(unsigned char key, int x, int y)
{
switch(key) {
case ESC:
exit(1);
}
}
void display(void)
{
float Pheta, Pheta2, Pheta3,Pheta4, Vo, time, time_top, d1, d2, d3, Uox1, Uox2, Uox3;
Vo = 60;
Pheta = 60;
Pheta2 = 30;
Pheta3 = 40;
Pheta4 = 50;
time = (2 * Vo * sin(Pheta * PI / 180)) / g;
time_top = time/2;
d1 = 500;
d2 = 650;
d3 = 800;
Uox1 = (d1 - Vo * cos(Pheta * PI / 180) * 2)/2;
Uox2 = (d2 - Vo * cos(Pheta * PI / 180)* time_top)/time_top;
Uox3 = (d3 - Vo * cos(Pheta * PI / 180) * 8)/8;
for(float t=0; t < 12 ; t += 0.0005)
{
float x1 = (Vo * cos(Pheta * PI / 180) * t);
float y1 = (Vo * sin(Pheta * PI / 180) * t - 0.5 * g * t * t);
float x2 = (d1 - Uox1 * t);
float y2 = (Vo * sin(Pheta * PI / 180) * t - 0.5 * g * t * t);
float x3 = (d2 - Uox2 * t);
float y3 = (Vo * sin(Pheta * PI / 180) * t - 0.5 * g * t * t);
float x4 = (d3 - Uox3 * t);
float y4 = (Vo * sin(Pheta * PI / 180) * t - 0.5 * g * t * t);
glBegin(GL_POINTS);
glVertex2d(x1, y1);
glVertex2d(x2, y2);
glVertex2d(x3, y3);
glVertex2d(x4, y4);
if (x1+0.1 >= x4 && x4+0.1 >= x1)
{
break;
}
glEnd();
glFlush();
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(800, 600);
glutInitWindowPosition(0, 0);
glutCreateWindow("C-Lang-Project");
glutKeyboardFunc(keyPressFunc);
initialize();
glutDisplayFunc(display);
glutMainLoop();
}
To make it 3D, I changed glVertex2d into glVertex3d, set a variable z and added it to the glVertex3d.
The final code that I've got:
#include <stdio.h>
#include <GL/glut.h>
#include <math.h>
#include <unistd.h>
#define g 9.8
#define PI 3.14
#define ESC 27
void initialize(void)
{
glClearColor(0, 0, 0, 0);
glColor3f(0.0, 1.0, 0.0);
glPointSize(3.0);
glEnable(GL_POINT_SMOOTH);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, 1000, 0, 500);
}
static void keyPressFunc(unsigned char key, int x, int y)
{
switch(key) {
case ESC:
exit(1);
}
}
void display(void)
{
float Pheta, Pheta2, Pheta3,Pheta4, Vo, time, time_top, d1, d2, d3, Uox1, Uox2, Uox3, z;
Vo = 60;
Pheta = 60;
Pheta2 = 30;
Pheta3 = 40;
Pheta4 = 50;
time = (2 * Vo * sin(Pheta * PI / 180)) / g;
time_top = time/2;
d1 = 500;
d2 = 650;
d3 = 800;
z = 15;
Uox1 = (d1 - Vo * cos(Pheta * PI / 180) * 2)/2;
Uox2 = (d2 - Vo * cos(Pheta * PI / 180)* time_top)/time_top;
Uox3 = (d3 - Vo * cos(Pheta * PI / 180) * 8)/8;
for(float t=0; t < 12 ; t += 0.0005)
{
float x1 = (Vo * cos(Pheta * PI / 180) * t);
float y1 = (Vo * sin(Pheta * PI / 180) * t - 0.5 * g * t * t);
float x2 = (d1 - Uox1 * t);
float y2 = (Vo * sin(Pheta * PI / 180) * t - 0.5 * g * t * t);
float x3 = (d2 - Uox2 * t);
float y3 = (Vo * sin(Pheta * PI / 180) * t - 0.5 * g * t * t);
float x4 = (d3 - Uox3 * t);
float y4 = (Vo * sin(Pheta * PI / 180) * t - 0.5 * g * t * t);
glBegin(GL_POINTS);
glVertex3d(x1, y1, z);
glVertex3d(x2, y2, z);
glVertex3d(x3, y3, z);
glVertex3d(x4, y4, z);
if (x1+0.1 >= x4 && x4+0.1 >= x1)
{
break;
}
glEnd();
glFlush();
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(800, 600);
glutInitWindowPosition(0, 0);
glutCreateWindow("C-Lang-Project");
glutKeyboardFunc(keyPressFunc);
initialize();
glutDisplayFunc(display);
glutMainLoop();
}
But it does not show any mistake, just shows a black window.
P.S. I am using OpenGL & freeglut
The scene is clipped by by the near plane of the orthographic projection.
The z coordiante of the geoemtry is set z=15; but the orthographic projection is set gluOrtho2D(0, 1000, 0, 500);. gluOrtho2D sets a near plane of -1 and a far plane of 1.
The view space z coordinate has to be between the near and far plane.
Since the view space z axis points out of the viewport, the view space z coordinate is -15.
This means, if z=15 then the following condition has to be fulfilled:
near < -15 < far
Change the orthographic projection to solve the issue. Use glOrtho:
e.g.
void initialize(void)
{
// [...]
glOrtho(0, 1000, 0, 500, -20, 1);
}
Of course it is possible to switch to perspective projection. In this case you've to invert the and z coordinate.
To get all the geometry on the screen (in clip space), I recommend to increase the amount to of the z coordinate and (of course) the distance to the far plane:
e.g.
void display(void)
{
float z = -500;
// [...]
}
void initialize(void)
{
// [...]
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective( 90.0, 1000.0 / 500.0, 0.1, 1000.0 );
}
Don't implement a render loop in the event processing loop. Use glutPostRedisplay to force the display to be repainted:
float t=0;
void display(void)
{
float Pheta, Pheta2, Pheta3,Pheta4, Vo, time, time_top, d1, d2, d3, Uox1, Uox2, Uox3, z;
Vo = 60; Pheta = 60; Pheta2 = 30; Pheta3 = 40; Pheta4 = 50;
time = (2 * Vo * sin(Pheta * PI / 180)) / g;
time_top = time/2; d1 = 500; d2 = 650; d3 = 800;
z = 15;
Uox1 = (d1 - Vo * cos(Pheta * PI / 180) * 2)/2;
Uox2 = (d2 - Vo * cos(Pheta * PI / 180)* time_top)/time_top;
Uox3 = (d3 - Vo * cos(Pheta * PI / 180) * 8)/8;
float x1 = (Vo * cos(Pheta * PI / 180) * t);
float y1 = (Vo * sin(Pheta * PI / 180) * t - 0.5 * g * t * t);
float x2 = (d1 - Uox1 * t);
float y2 = (Vo * sin(Pheta * PI / 180) * t - 0.5 * g * t * t);
float x3 = (d2 - Uox2 * t);
float y3 = (Vo * sin(Pheta * PI / 180) * t - 0.5 * g * t * t);
float x4 = (d3 - Uox3 * t);
float y4 = (Vo * sin(Pheta * PI / 180) * t - 0.5 * g * t * t);
glBegin(GL_POINTS);
glVertex3d(x1, y1, z);
glVertex3d(x2, y2, z);
glVertex3d(x3, y3, z);
glVertex3d(x4, y4, z);
glEnd();
t += 0.0005;
glFlush();
glutPostRedisplay();
}
Related
I am currently writing my own game engine and I am having trouble properly implementing quaternions. My current quaternion implementation looks like this:
/*
CybRender - Quaternion API
*/
#include "CybQuat.h"
//Functions
//=================================================================================
void Cyb_QuatFromAxisAndAngle(Cyb_Vec4 *quat, float x, float y, float z,
float angle)
{
quat->x = x * sinf(radians(angle) / 2.0f);
quat->y = y * sinf(radians(angle) / 2.0f);
quat->z = z * sinf(radians(angle) / 2.0f);
quat->w = cosf(radians(angle) / 2.0f);
}
void Cyb_MulQuat(Cyb_Vec4 *c, const Cyb_Vec4 *a, const Cyb_Vec4 *b)
{
c->x = a->w * b->x + a->x * b->w + a->y * b->z - a->z * b->y;
c->y = a->w * b->y - a->x * b->z + a->y * b->w + a->z * b->x;
c->z = a->w * b->z + a->x * b->y - a->y * b->x + a->z * b->w;
c->w = a->w * b->w - a->x * b->x - a->y * b->y - a->z * b->z;
}
void Cyb_QuatToMatrix(Cyb_Mat4 *mat, const Cyb_Vec4 *quat)
{
//Start with the identity matrix
Cyb_Identity(mat);
//Row 1
mat->a = 1 - 2 * quat->y * quat->y - 2 * quat->z * quat->z;
mat->b = 2 * quat->x * quat->y - 2 * quat->w * quat->z;
mat->c = 2 * quat->x * quat->z + 2 * quat->w * quat->y;
//Row 2
mat->e = 2 * quat->x * quat->y + 2 * quat->w * quat->z;
mat->f = 1 - 2 * quat->x * quat->x - 2 * quat->z * quat->z;
mat->g = 2 * quat->y * quat->z + 2 * quat->w * quat->x;
//Row 3
mat->i = 2 * quat->x * quat->z - 2 * quat->w * quat->y;
mat->j = 2 * quat->y * quat->z - 2 * quat->w * quat->x;
mat->k = 1 - 2 * quat->x * quat->x - 2 * quat->y * quat->y;
}
It works properly if I only rotate around the X, Y, or Z axis. However, when I try to rotate around an arbitrary axis, I get odd distortion:
I have tried different formulas for converting my quaternion to a matrix, but every time I get similar distortion. I already tested my matrix implementation to make sure it was working correctly and found no problems with it.
What is the correct formula for converting a quaternion to a matrix?
It turned out to be a minor mistake in the function that converts a quaternion to a matrix. Here is the corrected code:
/*
CybRender - Quaternion API
*/
#include "CybQuat.h"
//Functions
//=================================================================================
void Cyb_QuatFromAxisAndAngle(Cyb_Vec4 *quat, float x, float y, float z,
float angle)
{
quat->x = x * sinf(radians(angle) / 2.0f);
quat->y = y * sinf(radians(angle) / 2.0f);
quat->z = z * sinf(radians(angle) / 2.0f);
quat->w = cosf(radians(angle) / 2.0f);
}
void Cyb_MulQuat(Cyb_Vec4 *c, const Cyb_Vec4 *a, const Cyb_Vec4 *b)
{
c->x = a->w * b->x + a->x * b->w + a->y * b->z - a->z * b->y;
c->y = a->w * b->y - a->x * b->z + a->y * b->w + a->z * b->x;
c->z = a->w * b->z + a->x * b->y - a->y * b->x + a->z * b->w;
c->w = a->w * b->w - a->x * b->x - a->y * b->y - a->z * b->z;
}
void Cyb_NormalizeQuat(Cyb_Vec4 *quat)
{
float magnitude = sqrt(quat->x * quat->x + quat->y * quat->y + quat->z * quat->z + quat->w * quat->w);
quat->x /= magnitude;
quat->y /= magnitude;
quat->z /= magnitude;
quat->w /= magnitude;
}
void Cyb_QuatToMatrix(Cyb_Mat4 *mat, const Cyb_Vec4 *quat)
{
//Start with the identity matrix
Cyb_Identity(mat);
//Row 1
mat->a = 1.0f - 2.0f * (quat->y * quat->y + quat->z * quat->z);
mat->b = 2.0f * (quat->x * quat->y - quat->w * quat->z);
mat->c = 2.0f * (quat->x * quat->z + quat->w * quat->y);
//Row 2
mat->e = 2.0f * (quat->x * quat->y + quat->w * quat->z);
mat->f = 1.0f - 2.0f * (quat->x * quat->x + quat->z * quat->z);
mat->g = 2.0f * (quat->y * quat->z - quat->w * quat->x);
//Row 3
mat->i = 2.0f * (quat->x * quat->z - quat->w * quat->y);
mat->j = 2.0f * (quat->y * quat->z + quat->w * quat->x);
mat->k = 1.0f - 2.0f * (quat->x * quat->x + quat->y * quat->y);
}
I hope this will help other people who need to implement quaternions.
So, I wrote a little code to display to draw circles. It kinda works, but in a really janky way. This is the output of running the program and inputting 6:
O O
O O
O
O
O
O
O
O
O
O O
O O
OOOOOOO
Not looking great.
#include <stdio.h>
#include <math.h>
int main()
{
int num, dist, x, y;
printf("Enter the Radius of the Circle: ");
scanf_s("%d", &num);
{
for (x = 1; x <= num * 2; x++)
{
for (y = 1; y <= num * 2; y++)
{
dist = sqrt((x - num) * (x - num) + (y - num) * (y - num));
{
if (dist==num)
{
printf("O");
}
else
{
printf(" ");
}
}
}
printf("\n");
}
}
return 0;
}
This is the code, searched around the web for answers, it might be the placement of the "new line" code. Tried different spots, nope.
Your two for loop should start from 0:
for (x = 0; x <= num * 2; x++)
{
for (y = 0; y <= num * 2; y++)
{
dist = sqrt((x - num) * (x - num) + (y - num) * (y - num));
{
if (dist==num)
{
printf("O");
}
else
{
printf(" ");
}
}
}
printf("\n");
}
You are probably missing the first column and the first row.
I wrote one once, but mine just uses summations and subtractions, no multiplications (except one square, at the beginning) using The Bresenham Algorithm. Here is the code. (you can get it also from github)
/* bresenham.c -- program to draw ASCII circles with Bresenham's algorithm.
* Author: Luis Colorado <luicoloradourcola#gmail.com>
* Date: Wed Jan 11 10:50:17 EET 2017
* Disclaimer: (C) 2017 LUIS COLORADO. ALL RIGHTS RESERVED.
* BSD 3-Clause License
*
* Copyright (c) 2017, Luis Colorado
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#define FL_FILL (1 << 0)
#define FL_TRACE (1 << 1)
#define F(x) "%s:%d:%s: " x, __FILE__, __LINE__, __func__
/* draws a horizontal line at row y, between x1 and x2 */
static void hline(int x1, int x2, int y)
{
static char theLine[] =
"*****************************************"
"*****************************************"
"*****************************************"
"*****************************************"
"*****************************************"
"*****************************************"
"*****************************************"
"*****************************************"
"*****************************************"
"*****************************************"
"*****************************************"
"*****************************************";
#define THE_LINE_LENGTH (sizeof theLine - 1)
int count = (x2 - x1 + 1) << 1;
printf("\033[%d;%dH", y, x1<<1);
while (count >= THE_LINE_LENGTH) {
fputs(theLine, stdout);
count -= THE_LINE_LENGTH;
} /* while */
printf("%.*s", count, theLine);
} /* hline */
/* draws a dot at coordinates (x, y) */
static void dot(int x, int y)
{
printf("\033[%d;%dH*", y, x<<1);
} /* dot */
/* draws a circle of radius r and center at (cx, cy) */
void bh(int r, int cx, int cy, int flags)
{
int r2 = r*r + r;
int x = 0, x2 = 0, dx2 = 1;
int y = r, y2 = y*y, dy2 = 2*y - 1;
int sum = r2;
while(x <= y) {
if (flags & FL_TRACE) {
printf(F("x=%3d, x2=%5d, dx2=%3d, y=%3d, y2=%5d, dy2=%3d, sum=%5d\n"),
x, x2, dx2, y, y2, dy2, sum);
} else {
if (flags & FL_FILL) {
hline(cx - y, cx + y, cy + x);
if (x) hline(cx - y, cx + y, cy - x);
} else {
dot(cx - y, cy + x); if (y) dot(cx + y, cy + x);
if (x) { dot(cx - y, cy - x); if (y) dot(cx + y, cy - x); }
if (x != y) {
dot(cx - x, cy - y); if (x) dot(cx + x, cy - y);
if (y) { dot(cx - x, cy + y); if (x) dot(cx + x, cy + y); }
}
} /* if */
} /* if */
sum -= dx2;
if (sum <= y2) {
if (!(flags & FL_TRACE) && (flags & FL_FILL) && (x != y)) {
hline(cx - x, cx + x, cy - y);
if (y) hline(cx - x, cx + x, cy + y);
} /* if */
y--; y2 -= dy2; dy2 -= 2;
} /* if */
x++;
x2 += dx2;
dx2 += 2;
} /* while */
} /* bh */
int main(int argc, char **argv)
{
int i;
char *cols = getenv("COLUMNS");
char *lines = getenv("LINES");
int cx, cy;
int opt;
int flags = 0;
while ((opt = getopt(argc, argv, "fv")) != EOF) {
switch(opt) {
case 'f': flags |= FL_FILL; break;
case 'v': flags |= FL_TRACE; break;
} /* switch */
} /* while */
argc -= optind;
argv += optind;
if (cols && lines) {
cx = atoi(cols);
cy = atoi(lines);
} else { /* try to get from tty */
struct winsize win;
int res = ioctl(0, TIOCGWINSZ, &win);
if (res == 0) {
cx = win.ws_col;
cy = win.ws_row;
} else {
fprintf(stderr,
F("TIOCGWINSZ: %s (errno=%d)\n"),
strerror(errno), errno);
cx = 80; cy = 24;
} /* if */
} /* if */
/* center coordinates */
cx /= 4;
cy /= 2;
if (!(flags & FL_TRACE))
fputs("\033[2J", stdout);
for (i = 0; i < argc; i++) {
bh(atoi(argv[i]), cx, cy, flags);
} /* for */
if (!(flags & FL_TRACE)) {
puts("");
fflush(stdout);
} /* if */
} /* main */
it draws amazing circles like this:
$ bresenham 5 10
* * * * * * *
* * * *
* *
* *
$ _ * *
* * * * * * *
* * * *
* * * *
* * * *
* * * *
* * * *
* * * *
* * * *
* * * *
* * * *
* * * * * * *
* *
* *
* *
* * * *
* * * * * * *
a Mandelbrot set fractal using C programming and OpenGL. Here is my code. It is only displaying a dot in the center right now. I cannot figure out where I am going wrong. I'm pretty sure my math is correct. Maybe I have something in the wrong loop?
This picture is what Im trying to get
Here is my code so far:
#include <GLUT/glut.h>
#include <math.h>
void init(void);
void display(void);
const int screenWidth = 640;
const int screenHeight = 480;
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(screenWidth, screenHeight);
glutInitWindowPosition(0, 0);
glutCreateWindow("Mandelbrot");
// glViewport(-320, -320, 320, 320);
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
void init(void) {
glMatrixMode(GL_PROJECTION);
gluOrtho2D(-500.0, screenWidth, -500.0, screenHeight);
// A = screenWidth / 4.0;
// B = 0.0;
// C = D = screenHeight / 2.0;
}
void display(void) {
GLdouble x, f, y, xtemp, y0, x0, iteration, maxInteration;
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glPointSize(1);
glColor3f(0.0, 0.0, 0.0);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
for (y0 = - 1; y0 < 1.1; y0 = y0 + 0.0025) {
for (x0 = -2.5; x0 < 1.1; x0 = x0 + 0.0025) {
x = 0;
y = 0;
iteration = 0;
maxInteration = 1000;
while (((x * x) + (y * y) < (2 * 2)) && iteration < maxInteration) {
xtemp = (x * x) - (y * y) + x0;
y = (2 * x * y) + y0;
x = xtemp;
iteration = iteration + 1;
if (y <= 2) {
glBegin(GL_POINTS);
glVertex2d(x / 750, y / 750);
glEnd();
}
}
}
}
glFlush();
}
Here is my updated code after fixing suggestions in comments.. It results in the above image.. However, now I am trying to create the grey circles around the object??? Im attempting to do this through the else at the end... any thoughts?
#include <GLUT/glut.h>
#include <math.h>
void init(void);
void display(void);
const int screenWidth = 640;
const int screenHeight = 640;
GLdouble A, B, C, D;
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(screenWidth, screenHeight);
glutInitWindowPosition(0, 0);
glutCreateWindow("Mandelbrot");
glViewport(-1, 1, -1, 1);
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
void init(void) {
//glMatrixMode(GL_PROJECTION);
gluOrtho2D(-3.0, 3.0, -3.0, 3.0);
A = screenWidth / 4.0;
B = 0.0;
C = D = screenHeight / 2.0;
}
void display(void)
{
GLdouble x, f, y, xtemp, y0, x0, iteration, maxInteration;
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glPointSize(1);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
for(y0 = -1; y0< 1.1; y0 = y0 + 0.0025){
for (x0 = -2.5; x0 < 1.1; x0 = x0 + 0.0025) {
x = 0;
y = 0;
iteration = 0;
maxInteration = 200;
while(((x*x) + (y*y) <(2*2)) && iteration <maxInteration){
xtemp = (x*x) - (y*y) + x0;
y = (2*x*y) +y0;
x = xtemp;
iteration = iteration + 1;
}
if(iteration >= maxInteration){
glBegin(GL_POINTS);
glVertex2d(x0 , y0);
glColor3f(0.0, 0.0, 0.0);
glEnd();
}
else{
????
}
}
}
glFlush();
}
First of all, here's some advices regarding to your code:
When working with complex numbers or vectors i'd recommend you to use a proper fast math library so you can avoid operating with individual components, there are very fast cpu math libraries out there which can use SIMD instructions and your code will become more readable
The way your drawing the mandelbrot is really a bad idea. I mean, yeah, it's alright if you just want to dump simple images and learning the basics but that's pretty much. Don't use GL_POINTS and try to render/update textures directly, or even better, use fragment shaders + glsl (recommended way) so your mandelbrot will be rendered very fast even if you're using non-optimized maths.
Coordinate systems, if you still insist on using GL_POINTS the way you're doing, i'd just use directly the window coordinates and going from that space to the mandelbrot math domain ie: [0,0,w,h]<->[-1,-1,1,1]
Here's a little example of what i mean:
#include <GL/glut.h>
#include <math.h>
#include <stdio.h>
const int screen_width = 640;
const int screen_height = 480;
float c[4];
float z[4];
float clamp(float x, float vmin, float vmax) {
if (x < vmin) {
return vmin;
} else if (x > vmax) {
return vmax;
}
return x;
}
void dc_add(float *a, float *b, float *res) {
res[0] = a[0] + b[0];
res[1] = a[1] + b[1];
res[2] = a[2] + b[2];
res[3] = a[3] + b[3];
}
void dc_mul(float *a, float *b, float *res) {
res[0] = a[0] * b[0] - a[1] * b[1];
res[1] = a[0] * b[1] + a[1] * b[0];
res[2] = a[0] * b[2] + a[2] * b[0] - a[1] * b[3] - a[3] * b[1];
res[3] = a[0] * b[3] + a[3] * b[0] + a[2] * b[1] + a[1] * b[2];
}
void dc_sqr(float *a, float *res) {
res[0] = a[0] * a[0] - a[1] * a[1];
res[1] = 2.0f * a[0] * a[1];
res[2] = 2.0f * (a[0] * a[2] - a[1] * a[3]);
res[3] = 2.0f * (a[0] * a[3] + a[1] * a[2]);
}
float dot(float x, float y) { return x * x + y * y; }
void init(void) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, screen_width, 0, screen_height);
}
void display(void) {
glClear(GL_COLOR_BUFFER_BIT);
glPointSize(1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
for (int y = 0; y < screen_height; y++) {
for (int x = 0; x < screen_width; x++) {
float px = -1.0f + 2.0f * (float)x / (float)screen_width;
float py = -1.0f + 2.0f * (float)y / (float)screen_height;
px *= (float)screen_width / (float)screen_height;
float tz = 0.5f;
float zo = powf(1.2f, 1.2f);
float m2 = 0.0f;
float co = 0.0f;
float temp[4];
c[0] = px * zo; c[1] = py * zo; c[2] = 1.0; c[3] = 0.0;
z[0] = 0.0f; z[1] = 0.0f; z[2] = 0.0f; z[3] = 0.0f;
for (int i = 0; i < 256; i++) {
if (m2 > 1024.0f) continue;
dc_sqr(z, temp);
dc_add(temp, c, z);
m2 = dot(z[0], z[1]);
co += 1.0f;
}
float d = 0.0f;
if (co < 256.0f) {
d = sqrtf((dot(z[0], z[1]) / dot(z[2], z[3]))) *
logf(dot(z[0], z[1]));
}
d = clamp(4.0f * d / zo, 0.0f, 1.0f);
d = powf(d, 0.25f);
glColor3f(d, d, d);
glBegin(GL_POINTS);
glVertex2d(x, y);
glEnd();
}
}
glFlush();
glutSwapBuffers();
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(screen_width, screen_height);
glutInitWindowPosition(0, 0);
glutCreateWindow("Mandelbrot");
init();
glutDisplayFunc(display);
glutIdleFunc(display);
glutMainLoop();
return 0;
}
And here's the output:
Maths of the above example are based on this shadertoy.
The above code is terrible unefficient and slow but it serves the main purpose to prove you the way you shouldn't ever code a proper mandelbrot.
Happy coding.
There is a simple problem in you code: you use a division instead of a multiplication to compute the pixel coordinates: change glVertex2d(x / 750, y / 750); to
glVertex2d(x * 750, y * 750);
However, this is not the correct method to compute the Mandelbrot set. You should instead compute the number of iterations for the squared module to exceed 4.0, and then set the color of the pixel at (x0 * 300, y0 * 300) to that number as a palette entry or a gray level.
I have two 3D points: (x1, y1, z1) and (x3, y3, z3) and want to find a point (x2, y2, z2) on that line given z2, which is between z1 and z3.
Here is what I have currently:
#include<math.h>
#include<stdlib.h>
#include<stdio.h>
double *findPoint (double x1, double y1, double z1, double x3, double y3, double z3, double z2)
{
double *ret = malloc(3 * sizeof(double));
double dot = (x1 * x3) + (y1 * y3) + (z1 * z3);
printf("dot %e\n", dot);
double magprd = ((x1 * x1) + (y1 * y1) + (z1 * z1)) * ((x3 * x3) + (y3 * y3) + (z3 * z3));
printf("magprd %e\n", magprd);
double angle = acos(dot / magprd);
printf("angle %e\n", angle);
double distance = z2 / asin(angle);
printf("distance %e\n", distance);
double x2 = x1 - ((distance * x1) / 3);
double y2 = y1 - ((distance * y1) / 3);
ret[0] = x2;
ret[1] = y2;
ret[2] = z2;
return ret;
}
int main() {
// return pointer to array containing x2, y2, z2 corresponding to
// z=4 on line between point at x1, y1, z1 and x3, y3, z3
double *p = findPoint(1, 2, 3, 11, 12, 13, 4);
if(p) {
printf("point on line at z=4 is %e, %e, %e\n", p[0], p[1], p[2]);
free(p);
}
return 0;
}
This doesn't work properly, though:
$ clang -lm test.c -o test
$ ./test
dot 7.400000e+01
magprd 6.076000e+03
angle 1.558617e+00
distance nan
point on line at z=4 is nan, nan, 4.000000e+00
How can I fix findPoint so that it solves this problem? Thanks!
You math looks very complicated. I would suggest this code:
typedef struct { double x,y,z; } Point;
Point findPoint(Point a, Point b, double z) {
double dx = b.x - a.x;
double dy = b.y - a.y;
double dz = b.z - a.z;
if(dz == 0.0) {
// ERROR
return (Point){ 0,0,0 };
}
double p = (z - a.z) / dz;
return (Point){ a.x + p*dx, a.y + p*dy, a.z + p*dz };
}
If you do not want to use by value I suggest this:
int findPoint(const Point* a, const Point* b, double z, Point* c) {
double dx = b->x - a->x;
double dy = b->y - a->y;
double dz = b->z - a->z;
if(dz == 0.0) {
// ERROR
return 0;
}
double p = (z - a.z) / dz;
c->x = a.x + p*dx;
c->y = a.y + p*dy;
c->z = a.z + p*dz };
return 1;
}
Point* a = malloc(sizeof(Point));
a->x = 1;
a->y = 2;
a->z = 3;
Point* b = malloc(sizeof(Point));
b->x = 11;
b->y = 12;
b->z = 13;
Point* c = malloc(sizeof(Point));
if(findPoint(a,b,4,c)) {
printf("Result: %e %e %e\n", c->x, c->y, c->z);
}
else {
printf("Error!\n");
}
You can simplify your function to
double *findPoint (double x1, double y1, double z1, double x3, double y3, double z3, double z2)
{
double *ret = malloc(3 * sizeof(double));
double tmp = (z2 - z1)/(z3 - z1); // Assuming that z1 != z3
double x2 = x1 + tmp * (x3 - x1);
double y2 = y1 + tmp * (y3 - y1);
ret[0] = x2;
ret[1] = y2;
ret[2] = z2;
return ret;
}
That gives the result
point on line at z=4 is 2.000000e+00, 3.000000e+00, 4.000000e+00
I wrote a simple opengl application in C which plots sin(x). This is my current draw function which runs very slow. How do I have to convert this code to make use of the faster 'vertex array' mode?
list of variables and functions used:
N = total number of points
x1 = min(x)
x2 = max(x)
y1 = min(y)
y2 = max(y)
func(x) = sin(x)
and here's the entire code:
/* to compile, do:
$ gcc -o out simple.c -lglut
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h>
#include <time.h>
float xmin = -10, xmax = 10, ymin = -5, ymax = 5;
int nPoints = 3000;
/* function to calculate each data point */
float func(float x)
{
return sin(x);
}
/* plotting function - very slow */
void draw(float (* func)(float x), float x1, float x2, float y1, float y2, int N)
{
float x, dx = 1.0/N;
glPushMatrix();
glScalef(1.0 / (x2 - x1), 1.0 / (y2 - y1), 1.0);
glTranslatef(-x1, -y1, 0.0);
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINE_STRIP);
for(x = x1; x < x2; x += dx)
{
glVertex2f(x, func(x));
}
glEnd();
glPopMatrix();
};
/* Redrawing func */
void redraw(void)
{
clock_t start = clock();
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// -x, +x, -y, +y, number points
draw(func, xmin, xmax, ymin, ymax, nPoints);
glutSwapBuffers();
printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC);
};
/* Idle proc. Redisplays, if called. */
void idle(void)
{
// shift 'xmin' & 'xmax' by one.
xmin++;
xmax++;
glutPostRedisplay();
};
/* Key press processing */
void key(unsigned char c, int x, int y)
{
if(c == 27) exit(0);
};
/* Window reashape */
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1, 0, 1, -1, 1);
glMatrixMode(GL_MODELVIEW);
};
/* Main function */
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutCreateWindow("Graph plotter");
glutReshapeWindow(1024, 800);
glutPostRedisplay(); // This call may or may not be necessary
/* Register GLUT callbacks. */
glutDisplayFunc(redraw);
glutKeyboardFunc(key);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
/* Init the GL state */
glLineWidth(2.0);
/* Main loop */
glutMainLoop();
return 0;
}
In terms of LodePNG's C-style vector struct/functions:
// shared
vector pts;
vector_init( &pts, sizeof( float ) );
// whenever x1, x2, or N changes
vector_cleanup( &pts );
float x, dx = 1.0/N;
for(x = x1; x < x2; x += dx)
{
vector_resize( &pts, pts.size + 2 );
*(float*)vector_get( &pts, pts.size-2 ) = x;
*(float*)vector_get( &pts, pts.size-1 ) = func(x);
}
// whenever you want to draw
glPushMatrix();
glScalef(1.0 / (x2 - x1), 1.0 / (y2 - y1), 1.0);
glTranslatef(-x1, -y1, 0.0);
glColor3f(1.0, 1.0, 1.0);
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 2, GL_FLOAT, 0, (float*)pts.data );
glDrawArrays( GL_LINE_STRIP, 0, pts.size / 2 );
glDisableClientState( GL_VERTEX_ARRAY );
glPopMatrix();
EDIT: Complete code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h>
#include <time.h>
typedef struct vector /*dynamic vector of void* pointers. This one is used only by the deflate compressor*/
{
void* data;
size_t size; /*in groups of bytes depending on type*/
size_t allocsize; /*in bytes*/
unsigned typesize; /*sizeof the type you store in data*/
} vector;
static unsigned vector_resize(vector* p, size_t size) /*returns 1 if success, 0 if failure ==> nothing done*/
{
if(size * p->typesize > p->allocsize)
{
size_t newsize = size * p->typesize * 2;
void* data = realloc(p->data, newsize);
if(data)
{
p->allocsize = newsize;
p->data = data;
p->size = size;
}
else return 0;
}
else p->size = size;
return 1;
}
static void vector_cleanup(void* p)
{
((vector*)p)->size = ((vector*)p)->allocsize = 0;
free(((vector*)p)->data);
((vector*)p)->data = NULL;
}
static void vector_init(vector* p, unsigned typesize)
{
p->data = NULL;
p->size = p->allocsize = 0;
p->typesize = typesize;
}
static void* vector_get(vector* p, size_t index)
{
return &((char*)p->data)[index * p->typesize];
}
float xmin = -10, xmax = 10, ymin = -5, ymax = 5;
int nPoints = 3000;
vector pts;
/* function to calculate each data point */
float func(float x)
{
return sin(x);
}
void update(float (* func)(float x), float x1, float x2, int N)
{
float x, dx = 1.0/N;
vector_cleanup( &pts );
for(x = x1; x < x2; x += dx)
{
vector_resize( &pts, pts.size + 2 );
*(float*)vector_get( &pts, pts.size-2 ) = x;
*(float*)vector_get( &pts, pts.size-1 ) = func(x);
}
}
/* plotting function - very slow */
void draw(float x1, float x2, float y1, float y2)
{
glPushMatrix();
glScalef(1.0 / (x2 - x1), 1.0 / (y2 - y1), 1.0);
glTranslatef(-x1, -y1, 0.0);
glColor3f(1.0, 1.0, 1.0);
if( pts.size > 0 )
{
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 2, GL_FLOAT, 0, (float*)pts.data );
glDrawArrays( GL_LINE_STRIP, 0, pts.size / 2 );
glDisableClientState( GL_VERTEX_ARRAY );
}
glPopMatrix();
};
/* Redrawing func */
void redraw(void)
{
clock_t start = clock();
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// -x, +x, -y, +y, number points
draw(xmin, xmax, ymin, ymax);
glutSwapBuffers();
printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC);
};
/* Idle proc. Redisplays, if called. */
void idle(void)
{
// shift 'xmin' & 'xmax' by one.
xmin++;
xmax++;
update(func, xmin, xmax, nPoints);
glutPostRedisplay();
};
/* Key press processing */
void key(unsigned char c, int x, int y)
{
if(c == 27) exit(0);
};
/* Window reashape */
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1, 0, 1, -1, 1);
glMatrixMode(GL_MODELVIEW);
};
/* Main function */
int main(int argc, char **argv)
{
vector_init( &pts, sizeof( float ) );
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutCreateWindow("Graph plotter");
glutReshapeWindow(1024, 800);
glutPostRedisplay(); // This call may or may not be necessary
/* Register GLUT callbacks. */
glutDisplayFunc(redraw);
glutKeyboardFunc(key);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
/* Init the GL state */
glLineWidth(2.0);
/* Main loop */
glutMainLoop();
return 0;
}