Sunday, March 5, 2017
Tuesday, January 17, 2017
Stellated Octahedron
Snapshot:
This is a link to the wiki pages: https://en.wikipedia.org/wiki/Stellated_octahedron
https://en.wikipedia.org/wiki/Polyhedron_model which inspired this program.
Here is the source in Java OpenGL.
This is a link to the wiki pages: https://en.wikipedia.org/wiki/Stellated_octahedron
https://en.wikipedia.org/wiki/Polyhedron_model which inspired this program.
Here is the source in Java OpenGL.
Sunday, January 15, 2017
Points in 3D with gaussian Distribution
Snapshot:
In JOGL this is so easy that I was amazed. Im Trying to generate blobby objects. In the hearn and baker text book its mentioned that points in a gaussian distribution with a surface where the density of the points falls below a threshold is rendered. Will keep updated everyone if this does result in a blobby object.
This piece of code does the magic:
GL2 gl = arg0.getGL().getGL2();
for(int i=0;i<MAX_RAND;i++)
{
x[i]=1-randomno.nextGaussian()*2;
y[i]=1-randomno.nextGaussian()*2;
z[i]=1-randomno.nextGaussian()*2;
}
gl.glBegin(GL2.GL_POINTS);
for(int i=0;i<MAX_RAND;i++)
{
gl.glVertex3d(x[i],y[i],z[i]);
}
gl.glEnd();
Thanks!
In JOGL this is so easy that I was amazed. Im Trying to generate blobby objects. In the hearn and baker text book its mentioned that points in a gaussian distribution with a surface where the density of the points falls below a threshold is rendered. Will keep updated everyone if this does result in a blobby object.
This piece of code does the magic:
GL2 gl = arg0.getGL().getGL2();
for(int i=0;i<MAX_RAND;i++)
{
x[i]=1-randomno.nextGaussian()*2;
y[i]=1-randomno.nextGaussian()*2;
z[i]=1-randomno.nextGaussian()*2;
}
gl.glBegin(GL2.GL_POINTS);
for(int i=0;i<MAX_RAND;i++)
{
gl.glVertex3d(x[i],y[i],z[i]);
}
gl.glEnd();
Thanks!
Sunday, January 8, 2017
Car Viewer in TurboC++
This project was created several years back when I was not good at programming. I was a learner then. I knew very little of graphics. Yet I tried to rotate and do coordinate transformations. This project does viewing... For theory behind this refer James D Foley "Computer Graphics"
Snapshot:
It was supposed to be a car but without wheels.
I am pasting the source here itself for online viewing.
#include<stdio.h>
#include<graphics.h>
#include<conio.h>
#include<math.h>
#include<dos.h>
#include<stdlib.h>
typedef struct
{float x,y,z;
}point;
typedef struct
{float dx,dy,dz;
}vector;
typedef struct
{int v1,v2; //two vertices of an edge (index into vertices)
}edge;
/*typedef struct
{int e1,e2,e3,e4; //index into edges
}polygon;
*/
point vertices[40];
edge edges[50];
//polygon polymesh[20];
int noofpolygons,noofedges,noofvertices;
float cosx,sinx,cosy,siny,cosz,sinz,d,umin,umax,vmin,vmax;
float shxpar,shypar,sperx,spery,sperz,f,b;
point vrp,prp,cube[8];
vector vpn,vup={0,1,0},dop;
point transform( point p)
{
float x,y,z;
p.x=p.x-vrp.x; //translate by t(-vrp)
p.y=p.y-vrp.y;
p.z=p.z-vrp.z;
x=p.x; // rotate wrt y
p.x=p.x*cosy+p.z*siny;
p.z=-x*siny+p.z*cosy;
y=p.y; // rotate wrt x
p.y=p.y*cosx-p.z*sinx;
p.z=y*sinx+p.z*cosx;
x=p.x; // rotate wrt z
p.x=p.x*cosz-p.y*sinz;
p.y=x*sinz+p.y*cosz;
p.x=p.x-prp.x; // translate by t(-prp)
p.y=p.y-prp.y;
p.z=p.z-prp.z;
/* p.x=p.x+shxpar*p.z; //shear such that dop is z axis
p.y=p.y+shypar*p.z;
p.x*=sperx; // scale such that the size of view
p.y*=spery; // volume is canonical view volume
p.z*=sperz; */
p.x*=(d/p.z); // project onto proj n plane
p.y*=(d/p.z);
p.z=d;
return(p);
}
void findmcomp()
{float d1,d2,d3,x,y,z;
// rotate wrt y
d=prp.z;
d1=sqrt(vpn.dx*vpn.dx+vpn.dz*vpn.dz);
cosy=vpn.dz/d1;
siny=vpn.dx/d1;
vpn.dx=0;
vpn.dz=d1;
x=vup.dx;
vup.dx=vup.dx*cosy+vup.dz*siny;
vup.dz=-x*siny+vup.dz*cosy;
// rotate wrt x
d2=sqrt(vpn.dx*vpn.dx+vpn.dy*vpn.dy+vpn.dz*vpn.dz);
cosx=d1/d2;
sinx=vpn.dy/d2;
vpn.dy=0;
vpn.dz=d2;
y=vup.dy;
vup.dy=vup.dy*cosx-vup.dz*sinx;
vup.dz=y*sinx+vup.dz*cosx; // this will be zero;
// rotate wrt z
d3=sqrt(vup.dx*vup.dx+vup.dy*vup.dy);
cosz=1;//vup.dy/d3;
sinz=0;//vup.dx/d3;
vup.dx=0;
vup.dy=d3;
/* dop.dx=(umax-umin)/2-prp.x;
dop.dy=(vmax-vmin)/2-prp.y;
dop.dz=-prp.z;
shxpar=-dop.dx/dop.dz;
shypar=-dop.dy/dop.dz;
sperx=-2*prp.z/((umax-umin)*(-prp.z+b));
spery=-2*prp.z/((vmax-vmin)*(-prp.z+b));
sperz=-1/(-prp.z+b); */
}
void initializevertices()
{
/* car */
vertices[0].x=10;vertices[0].y=0;vertices[0].z=10; //0
vertices[1].x=50;vertices[1].y=0;vertices[1].z=10; //1
vertices[2].x=50;vertices[2].y=30;vertices[2].z=15; //2
vertices[3].x=10;vertices[3].y=30;vertices[3].z=15; //3
vertices[4].x=10;vertices[4].y=40;vertices[4].z=50; //4
vertices[5].x=50;vertices[5].y=40;vertices[5].z=50; //5
vertices[6].x=50;vertices[6].y=70;vertices[6].z=55; //6
vertices[7].x=10;vertices[7].y=70;vertices[7].z=55; //7
vertices[8].x=10;vertices[8].y=70;vertices[8].z=95; //8
vertices[9].x=50;vertices[9].y=70;vertices[9].z=95; //9
vertices[10].x=50;vertices[10].y=40;vertices[10].z=100; //10
vertices[11].x=10;vertices[11].y=40;vertices[11].z=100; //11
vertices[12].x=10;vertices[12].y=30;vertices[12].z=135; //12
vertices[13].x=50;vertices[13].y=30;vertices[13].z=135; //13
vertices[14].x=50;vertices[14].y=0;vertices[14].z=140; //14
vertices[15].x=10;vertices[15].y=0;vertices[15].z=140; //15
vertices[16].x=10;vertices[16].y=0;vertices[16].z=100; //16
vertices[17].x=50;vertices[17].y=0;vertices[17].z=100; // 17
vertices[18].x=50;vertices[18].y=0;vertices[18].z=95; //18
vertices[19].x=10;vertices[19].y=0;vertices[19].z=95; //19
vertices[20].x=10;vertices[20].y=0;vertices[20].z=55; //20
vertices[21].x=50;vertices[21].y=0;vertices[21].z=55; //21
vertices[22].x=50;vertices[22].y=0;vertices[22].z=50; //22
vertices[23].x=10;vertices[23].y=0;vertices[23].z=50; //23
vertices[24].x=50;vertices[24].y=40;vertices[24].z=30; //24
vertices[25].x=10;vertices[25].y=40;vertices[25].z=30; //25
vertices[26].x=50;vertices[26].y=40;vertices[26].z=115; //26
vertices[27].x=10;vertices[27].y=40;vertices[27].z=115; //27
}
void initializeedges()
{
/* car */
edges[0].v1=0;edges[0].v2=1; //1
edges[1].v1=1;edges[1].v2=2; //2
edges[2].v1=2;edges[2].v2=3; //3
edges[3].v1=3;edges[3].v2=0; //4
edges[4].v1=3;edges[4].v2=25; //5
edges[5].v1=4;edges[5].v2=5; //6
edges[6].v1=5;edges[6].v2=6; //7
edges[7].v1=6;edges[7].v2=7; //8
edges[8].v1=7;edges[8].v2=4; //9
edges[9].v1=7;edges[9].v2=8; //10
edges[10].v1=8;edges[10].v2=9; //11
edges[11].v1=9;edges[11].v2=10; //12
edges[12].v1=10;edges[12].v2=11; //13
edges[13].v1=11;edges[13].v2=8; //14
edges[14].v1=9;edges[14].v2=6; //15
edges[15].v1=27;edges[15].v2=11; //16
edges[16].v1=12;edges[16].v2=13; //17
edges[17].v1=10;edges[17].v2=26; //18
edges[18].v1=13;edges[18].v2=14; //19
edges[19].v1=14;edges[19].v2=15; //20
edges[20].v1=15;edges[20].v2=12; //21
edges[21].v1=15;edges[21].v2=16; //22
edges[22].v1=16;edges[22].v2=17; //23
edges[23].v1=17;edges[23].v2=14; //24
edges[24].v1=18;edges[24].v2=19; //25
edges[25].v1=19;edges[25].v2=20; //26
edges[26].v1=20;edges[26].v2=21; //27
edges[27].v1=21;edges[27].v2=18; //28
edges[28].v1=22;edges[28].v2=23; //29
edges[29].v1=23;edges[29].v2=0; //30
edges[30].v1=22;edges[30].v2=1; //31
edges[31].v1=24;edges[31].v2=2; //32
edges[32].v1=24;edges[32].v2=25; //33
edges[33].v1=25;edges[33].v2=4; //34
edges[34].v1=24;edges[34].v2=5; //35
edges[35].v1=26;edges[35].v2=27; //36
edges[36].v1=27;edges[36].v2=12; //37
edges[37].v1=26;edges[37].v2=13; //38
edges[38].v1=5;edges[38].v2=22; //38
edges[39].v1=4;edges[39].v2=23; //38
edges[40].v1=10;edges[40].v2=17; //38
edges[41].v1=11;edges[41].v2=16; //38
edges[42].v1=5;edges[42].v2=10; //38
edges[43].v1=4;edges[43].v2=11; //38
}
void initializepolymesh()
{
}
void initializeobjects()
{
initializevertices();
initializeedges();
initializepolymesh();
}
void display()
{
for(int i=0;i<44;i++)
line(vertices[edges[i].v1].x+320,240+vertices[edges[i].v1].y,vertices[edges[i].v2].x+320,240+vertices[edges[i].v2].y);
}
void findvrpprpvpn(float theta)
{ float rtheta1,rtheta2,lvpn;
rtheta1=theta*3.141/180;
rtheta2=(theta+180)*3.141/180;
vrp.x=20*cos(rtheta1)+30;
vrp.z=20*sin(rtheta1)+75;
vrp.y=120;
prp.x=50*cos(rtheta2)+30;
prp.z=50*sin(rtheta2)+30;
prp.y=130;
vpn.dx=vrp.x-prp.x;
vpn.dy=vrp.y-prp.y;
vpn.dz=vrp.z-prp.z;
lvpn=sqrt(vpn.dx*vpn.dx+vpn.dy*vpn.dy+vpn.dz*vpn.dz);
vpn.dx=vpn.dx/lvpn;
vpn.dy=vpn.dy/lvpn;
vpn.dz=vpn.dz/lvpn;
// putpixel(prp.x+320,240-prp.z,WHITE);
prp.x=0;
prp.y=0;
prp.z=120;
}
void main()
{
int gd=DETECT,gm;
float theta;
char text[10];
initgraph(&gd,&gm,"c:\\tc\\bgi");
moveto(0,0);
theta=0;
while(!kbhit())
{findvrpprpvpn(theta);
findmcomp();
initializeobjects();
for(int i=0;i<32;i++)
vertices[i]=transform(vertices[i]);
delay(50);
cleardevice();
display();
theta+=0.1;
if(theta>360) theta=0;
}
getch();
closegraph();
}
Very soon I will modify the code to perform 3D viewing from any arbitrary position. Currently I am assuming many things. Will post the modified code soon. Several bugs in the software... got confused with x,y and z axis.
Snapshot:
It was supposed to be a car but without wheels.
I am pasting the source here itself for online viewing.
#include<stdio.h>
#include<graphics.h>
#include<conio.h>
#include<math.h>
#include<dos.h>
#include<stdlib.h>
typedef struct
{float x,y,z;
}point;
typedef struct
{float dx,dy,dz;
}vector;
typedef struct
{int v1,v2; //two vertices of an edge (index into vertices)
}edge;
/*typedef struct
{int e1,e2,e3,e4; //index into edges
}polygon;
*/
point vertices[40];
edge edges[50];
//polygon polymesh[20];
int noofpolygons,noofedges,noofvertices;
float cosx,sinx,cosy,siny,cosz,sinz,d,umin,umax,vmin,vmax;
float shxpar,shypar,sperx,spery,sperz,f,b;
point vrp,prp,cube[8];
vector vpn,vup={0,1,0},dop;
point transform( point p)
{
float x,y,z;
p.x=p.x-vrp.x; //translate by t(-vrp)
p.y=p.y-vrp.y;
p.z=p.z-vrp.z;
x=p.x; // rotate wrt y
p.x=p.x*cosy+p.z*siny;
p.z=-x*siny+p.z*cosy;
y=p.y; // rotate wrt x
p.y=p.y*cosx-p.z*sinx;
p.z=y*sinx+p.z*cosx;
x=p.x; // rotate wrt z
p.x=p.x*cosz-p.y*sinz;
p.y=x*sinz+p.y*cosz;
p.x=p.x-prp.x; // translate by t(-prp)
p.y=p.y-prp.y;
p.z=p.z-prp.z;
/* p.x=p.x+shxpar*p.z; //shear such that dop is z axis
p.y=p.y+shypar*p.z;
p.x*=sperx; // scale such that the size of view
p.y*=spery; // volume is canonical view volume
p.z*=sperz; */
p.x*=(d/p.z); // project onto proj n plane
p.y*=(d/p.z);
p.z=d;
return(p);
}
void findmcomp()
{float d1,d2,d3,x,y,z;
// rotate wrt y
d=prp.z;
d1=sqrt(vpn.dx*vpn.dx+vpn.dz*vpn.dz);
cosy=vpn.dz/d1;
siny=vpn.dx/d1;
vpn.dx=0;
vpn.dz=d1;
x=vup.dx;
vup.dx=vup.dx*cosy+vup.dz*siny;
vup.dz=-x*siny+vup.dz*cosy;
// rotate wrt x
d2=sqrt(vpn.dx*vpn.dx+vpn.dy*vpn.dy+vpn.dz*vpn.dz);
cosx=d1/d2;
sinx=vpn.dy/d2;
vpn.dy=0;
vpn.dz=d2;
y=vup.dy;
vup.dy=vup.dy*cosx-vup.dz*sinx;
vup.dz=y*sinx+vup.dz*cosx; // this will be zero;
// rotate wrt z
d3=sqrt(vup.dx*vup.dx+vup.dy*vup.dy);
cosz=1;//vup.dy/d3;
sinz=0;//vup.dx/d3;
vup.dx=0;
vup.dy=d3;
/* dop.dx=(umax-umin)/2-prp.x;
dop.dy=(vmax-vmin)/2-prp.y;
dop.dz=-prp.z;
shxpar=-dop.dx/dop.dz;
shypar=-dop.dy/dop.dz;
sperx=-2*prp.z/((umax-umin)*(-prp.z+b));
spery=-2*prp.z/((vmax-vmin)*(-prp.z+b));
sperz=-1/(-prp.z+b); */
}
void initializevertices()
{
/* car */
vertices[0].x=10;vertices[0].y=0;vertices[0].z=10; //0
vertices[1].x=50;vertices[1].y=0;vertices[1].z=10; //1
vertices[2].x=50;vertices[2].y=30;vertices[2].z=15; //2
vertices[3].x=10;vertices[3].y=30;vertices[3].z=15; //3
vertices[4].x=10;vertices[4].y=40;vertices[4].z=50; //4
vertices[5].x=50;vertices[5].y=40;vertices[5].z=50; //5
vertices[6].x=50;vertices[6].y=70;vertices[6].z=55; //6
vertices[7].x=10;vertices[7].y=70;vertices[7].z=55; //7
vertices[8].x=10;vertices[8].y=70;vertices[8].z=95; //8
vertices[9].x=50;vertices[9].y=70;vertices[9].z=95; //9
vertices[10].x=50;vertices[10].y=40;vertices[10].z=100; //10
vertices[11].x=10;vertices[11].y=40;vertices[11].z=100; //11
vertices[12].x=10;vertices[12].y=30;vertices[12].z=135; //12
vertices[13].x=50;vertices[13].y=30;vertices[13].z=135; //13
vertices[14].x=50;vertices[14].y=0;vertices[14].z=140; //14
vertices[15].x=10;vertices[15].y=0;vertices[15].z=140; //15
vertices[16].x=10;vertices[16].y=0;vertices[16].z=100; //16
vertices[17].x=50;vertices[17].y=0;vertices[17].z=100; // 17
vertices[18].x=50;vertices[18].y=0;vertices[18].z=95; //18
vertices[19].x=10;vertices[19].y=0;vertices[19].z=95; //19
vertices[20].x=10;vertices[20].y=0;vertices[20].z=55; //20
vertices[21].x=50;vertices[21].y=0;vertices[21].z=55; //21
vertices[22].x=50;vertices[22].y=0;vertices[22].z=50; //22
vertices[23].x=10;vertices[23].y=0;vertices[23].z=50; //23
vertices[24].x=50;vertices[24].y=40;vertices[24].z=30; //24
vertices[25].x=10;vertices[25].y=40;vertices[25].z=30; //25
vertices[26].x=50;vertices[26].y=40;vertices[26].z=115; //26
vertices[27].x=10;vertices[27].y=40;vertices[27].z=115; //27
}
void initializeedges()
{
/* car */
edges[0].v1=0;edges[0].v2=1; //1
edges[1].v1=1;edges[1].v2=2; //2
edges[2].v1=2;edges[2].v2=3; //3
edges[3].v1=3;edges[3].v2=0; //4
edges[4].v1=3;edges[4].v2=25; //5
edges[5].v1=4;edges[5].v2=5; //6
edges[6].v1=5;edges[6].v2=6; //7
edges[7].v1=6;edges[7].v2=7; //8
edges[8].v1=7;edges[8].v2=4; //9
edges[9].v1=7;edges[9].v2=8; //10
edges[10].v1=8;edges[10].v2=9; //11
edges[11].v1=9;edges[11].v2=10; //12
edges[12].v1=10;edges[12].v2=11; //13
edges[13].v1=11;edges[13].v2=8; //14
edges[14].v1=9;edges[14].v2=6; //15
edges[15].v1=27;edges[15].v2=11; //16
edges[16].v1=12;edges[16].v2=13; //17
edges[17].v1=10;edges[17].v2=26; //18
edges[18].v1=13;edges[18].v2=14; //19
edges[19].v1=14;edges[19].v2=15; //20
edges[20].v1=15;edges[20].v2=12; //21
edges[21].v1=15;edges[21].v2=16; //22
edges[22].v1=16;edges[22].v2=17; //23
edges[23].v1=17;edges[23].v2=14; //24
edges[24].v1=18;edges[24].v2=19; //25
edges[25].v1=19;edges[25].v2=20; //26
edges[26].v1=20;edges[26].v2=21; //27
edges[27].v1=21;edges[27].v2=18; //28
edges[28].v1=22;edges[28].v2=23; //29
edges[29].v1=23;edges[29].v2=0; //30
edges[30].v1=22;edges[30].v2=1; //31
edges[31].v1=24;edges[31].v2=2; //32
edges[32].v1=24;edges[32].v2=25; //33
edges[33].v1=25;edges[33].v2=4; //34
edges[34].v1=24;edges[34].v2=5; //35
edges[35].v1=26;edges[35].v2=27; //36
edges[36].v1=27;edges[36].v2=12; //37
edges[37].v1=26;edges[37].v2=13; //38
edges[38].v1=5;edges[38].v2=22; //38
edges[39].v1=4;edges[39].v2=23; //38
edges[40].v1=10;edges[40].v2=17; //38
edges[41].v1=11;edges[41].v2=16; //38
edges[42].v1=5;edges[42].v2=10; //38
edges[43].v1=4;edges[43].v2=11; //38
}
void initializepolymesh()
{
}
void initializeobjects()
{
initializevertices();
initializeedges();
initializepolymesh();
}
void display()
{
for(int i=0;i<44;i++)
line(vertices[edges[i].v1].x+320,240+vertices[edges[i].v1].y,vertices[edges[i].v2].x+320,240+vertices[edges[i].v2].y);
}
void findvrpprpvpn(float theta)
{ float rtheta1,rtheta2,lvpn;
rtheta1=theta*3.141/180;
rtheta2=(theta+180)*3.141/180;
vrp.x=20*cos(rtheta1)+30;
vrp.z=20*sin(rtheta1)+75;
vrp.y=120;
prp.x=50*cos(rtheta2)+30;
prp.z=50*sin(rtheta2)+30;
prp.y=130;
vpn.dx=vrp.x-prp.x;
vpn.dy=vrp.y-prp.y;
vpn.dz=vrp.z-prp.z;
lvpn=sqrt(vpn.dx*vpn.dx+vpn.dy*vpn.dy+vpn.dz*vpn.dz);
vpn.dx=vpn.dx/lvpn;
vpn.dy=vpn.dy/lvpn;
vpn.dz=vpn.dz/lvpn;
// putpixel(prp.x+320,240-prp.z,WHITE);
prp.x=0;
prp.y=0;
prp.z=120;
}
void main()
{
int gd=DETECT,gm;
float theta;
char text[10];
initgraph(&gd,&gm,"c:\\tc\\bgi");
moveto(0,0);
theta=0;
while(!kbhit())
{findvrpprpvpn(theta);
findmcomp();
initializeobjects();
for(int i=0;i<32;i++)
vertices[i]=transform(vertices[i]);
delay(50);
cleardevice();
display();
theta+=0.1;
if(theta>360) theta=0;
}
getch();
closegraph();
}
Very soon I will modify the code to perform 3D viewing from any arbitrary position. Currently I am assuming many things. Will post the modified code soon. Several bugs in the software... got confused with x,y and z axis.
Wednesday, December 21, 2016
Bicycle Riding
Copyright rests with the author Muhammed Tariq Siddiqui at the following site(Planet-source-code).
I ran the program and found out it requires no modification to run in ubuntu.
SnapShot:
This program has used quadric surfaces such gluDisk, gluCylinder and gluSphere which are tesselations of disks and partial disks or arcs.
I ran the program and found out it requires no modification to run in ubuntu.
SnapShot:
This program has used quadric surfaces such gluDisk, gluCylinder and gluSphere which are tesselations of disks and partial disks or arcs.
Tuesday, November 1, 2016
Conway's Game of Life
Conway was interested in a problem presented in the 1940s by mathematician John von Neumann,
who attempted to find a hypothetical machine that could build copies of
itself and succeeded when he found a mathematical model for such a
machine with very complicated rules on a rectangular grid. The Game of
Life emerged as Conway's successful attempt to drastically simplify von
Neumann's ideas. The game made its first public appearance in the
October 1970 issue of Scientific American, in Martin Gardner's "Mathematical Games" column. From a theoretical point of view, it is interesting because it has the power of a universal Turing machine: that is, anything that can be computed algorithmic-ally can be computed within Conway's Game of Life.
The rules of the game can be found all around the Internet. I have created a mesh of cells with randomly assigned values of alive or dead. Then iterated thorugh the mesh of cells and toggled according to the rules.
Snapshot:
Here is the source.
The rules of the game can be found all around the Internet. I have created a mesh of cells with randomly assigned values of alive or dead. Then iterated thorugh the mesh of cells and toggled according to the rules.
Snapshot:
Here is the source.
I could have easily thought about making this game of life in Javascript which would be like click on a few squares in the blog and just click play to see the result.. I thought that would be taxing on the minds so let this random generation be.
Saturday, October 29, 2016
Image Editing Using GIMP
You may have seen outputs of a few of the projects in the past. I have created this 640x480 image using GIMP. Graphical Image Manipulation Tool allows you to work with layers and create appealing posters or banners. If you are new to graphics this is the place to start your work in it.
Created this picture:
As can be seen... these images were opened as layers scaled,rotated,sheared and translated and blended with other layers with different opacity and blending mode while merging. All these are skills you could hone to make a living as a graphic designer.
Subscribe to:
Comments (Atom)





