Skip to content

Instantly share code, notes, and snippets.

@elbosso
Created January 10, 2021 15:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save elbosso/5cea6a07d0c238b315acfc2643b5826a to your computer and use it in GitHub Desktop.
Save elbosso/5cea6a07d0c238b315acfc2643b5826a to your computer and use it in GitHub Desktop.
Source to generate somewhat pretty graphics (abstract, generative art) - see also https://mastodon.social/@elbosso/105526549344085753 Creates "/tmp/render.png" upon execution in three different modes: 0,1,2. Tons of other parameters adjustable by altering the source code. Inspired by https://pixelfed.social/p/y6nH/38965 and https://www.scratchap…
/*
* Copyright (c) 2021.
*
* Juergen Key. Alle Rechte vorbehalten.
*
* Weiterverbreitung und Verwendung in nichtkompilierter oder kompilierter Form,
* mit oder ohne Veraenderung, sind unter den folgenden Bedingungen zulaessig:
*
* 1. Weiterverbreitete nichtkompilierte Exemplare muessen das obige Copyright,
* die Liste der Bedingungen und den folgenden Haftungsausschluss im Quelltext
* enthalten.
* 2. Weiterverbreitete kompilierte Exemplare muessen das obige Copyright,
* die Liste der Bedingungen und den folgenden Haftungsausschluss in der
* Dokumentation und/oder anderen Materialien, die mit dem Exemplar verbreitet
* werden, enthalten.
* 3. Weder der Name des Autors noch die Namen der Beitragsleistenden
* duerfen zum Kennzeichnen oder Bewerben von Produkten, die von dieser Software
* abgeleitet wurden, ohne spezielle vorherige schriftliche Genehmigung verwendet
* werden.
*
* DIESE SOFTWARE WIRD VOM AUTOR UND DEN BEITRAGSLEISTENDEN OHNE
* JEGLICHE SPEZIELLE ODER IMPLIZIERTE GARANTIEN ZUR VERFUEGUNG GESTELLT, DIE
* UNTER ANDEREM EINSCHLIESSEN: DIE IMPLIZIERTE GARANTIE DER VERWENDBARKEIT DER
* SOFTWARE FUER EINEN BESTIMMTEN ZWECK. AUF KEINEN FALL IST DER AUTOR
* ODER DIE BEITRAGSLEISTENDEN FUER IRGENDWELCHE DIREKTEN, INDIREKTEN,
* ZUFAELLIGEN, SPEZIELLEN, BEISPIELHAFTEN ODER FOLGENDEN SCHAEDEN (UNTER ANDEREM
* VERSCHAFFEN VON ERSATZGUETERN ODER -DIENSTLEISTUNGEN; EINSCHRAENKUNG DER
* NUTZUNGSFAEHIGKEIT; VERLUST VON NUTZUNGSFAEHIGKEIT; DATEN; PROFIT ODER
* GESCHAEFTSUNTERBRECHUNG), WIE AUCH IMMER VERURSACHT UND UNTER WELCHER
* VERPFLICHTUNG AUCH IMMER, OB IN VERTRAG, STRIKTER VERPFLICHTUNG ODER
* UNERLAUBTE HANDLUNG (INKLUSIVE FAHRLAESSIGKEIT) VERANTWORTLICH, AUF WELCHEM
* WEG SIE AUCH IMMER DURCH DIE BENUTZUNG DIESER SOFTWARE ENTSTANDEN SIND, SOGAR,
* WENN SIE AUF DIE MOEGLICHKEIT EINES SOLCHEN SCHADENS HINGEWIESEN WORDEN SIND.
*
*/
//https://pixelfed.social/p/y6nH/38965
//https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/building-basic-perspective-projection-matrix
import java.awt.*;
import java.awt.geom.Path2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Arrays;
import java.awt.geom.Point2D;
class RandomColor
{
private static final float golden_ratio_conjugate = 0.618033988749895f;
float h;
float s;
float b;
float alpha;
private final java.util.Random random;
public RandomColor()
{
this(System.currentTimeMillis(),1,1,1);
}
public RandomColor(long seed,float s,float b,float alpha)
{
super();
random=new java.util.Random(seed);
init(s,b,alpha);
}
private final void init(float s,float b,float alpha)
{
h=random.nextFloat();
this.s=s;
this.b=b;
this.alpha=alpha;
}
public Color next()
{
java.awt.Color rv=java.awt.Color.getHSBColor(h, s, b);
float []rgb=rv.getRGBComponents(null);
rv=new java.awt.Color(rgb[0], rgb[1], rgb[2], alpha);
h += golden_ratio_conjugate;
h %= 1;
return rv;
}
}
interface Constants
{
final static int X=0;
final static int Y=1;
final static int Z=2;
final static int W=3;
}
class Vec3 implements Constants
{
final double[] elements=new double[3];
public Vec3()
{
super();
for(int i=0;i< elements.length;++i)
elements[i]=0.0;
}
public Vec3(double... src)
{
this();
for(int i=0;i<src.length;++i)
elements[i]=src[i];
}
public double getX()
{
return elements[X];
}
public double getY()
{
return elements[Y];
}
public double getZ()
{
return elements[Z];
}
public Vec3 addAndNew(double... coords)
{
double[] el=Arrays.copyOf(elements,elements.length);
for(int i=0;i<coords.length;++i)
el[i]+=coords[i];
return new Vec3(el);
}
public java.awt.geom.Point2D toPoint2D()
{
return new Point2D.Double(elements[X],elements[Y]);
}
@Override
public String toString()
{
return "Vec3{" +
"elements=" + Arrays.toString(elements) +
'}';
}
}
public class Matrix44 implements Constants
{
final double[][] elements=new double[4][4];
static Matrix44 buildPerspectiveMatrix(double angleOfViewInDeg, double near, double far)
{
Matrix44 rv=new Matrix44();
// set the basic projection matrix
double scale = 1.0 / java.lang.Math.tan(angleOfViewInDeg * 0.5 * Math.PI / 180.0);
//double scale = 1.0 / java.lang.Math.tan(java.lang.Math.toRadians(angleOfViewInDeg));
rv.elements[0][0] = scale; // scale the x coordinates of the projected point
rv.elements[1][1] = scale; // scale the y coordinates of the projected point
rv.elements[2][2] = -far / (far - near); // used to remap z to [0,1]
rv.elements[3][2] = -far * near / (far - near); // used to remap z [0,1]
rv.elements[2][3] = -1; // set w = -z
rv.elements[3][3] = 0;
return rv;
}
static Matrix44 buildAffineTranslateMatrix(double tx, double ty, double tz)
{
Matrix44 rv=new Matrix44();
rv.elements[0][0]=1;
rv.elements[1][1]=1;
rv.elements[2][2]=1;
rv.elements[3][0]=tx;
rv.elements[3][1]=ty;
rv.elements[3][2]=tz;
rv.elements[3][3]=1;
return rv;
}
static Matrix44 buildAffineScaleMatrix(double sx, double sy, double sz)
{
Matrix44 rv=new Matrix44();
rv.elements[0][0]=sx;
rv.elements[1][1]=sy;
rv.elements[2][2]=sz;
rv.elements[3][3]=1;
return rv;
}
static Matrix44 buildAffineRotateAroundZMatrix(double thetaInDeg)
{
Matrix44 rv=new Matrix44();
double thetaRan=java.lang.Math.toRadians(thetaInDeg);
rv.elements[0][0]=java.lang.Math.cos(thetaRan);
rv.elements[0][1]=-java.lang.Math.sin(thetaRan);
rv.elements[1][0]=java.lang.Math.sin(thetaRan);
rv.elements[1][1]=java.lang.Math.cos(thetaRan);
rv.elements[2][2]=1;
rv.elements[3][3]=1;
return rv;
}
static Matrix44 buildIdentity(double thetaInDeg)
{
Matrix44 rv=new Matrix44();
double thetaRan=java.lang.Math.toRadians(thetaInDeg);
rv.elements[0][0]=1;
rv.elements[1][1]=1;
rv.elements[2][2]=1;
rv.elements[3][3]=1;
return rv;
}
public Matrix44()
{
super();
for(int row=0;row<4;++row)
{
for(int col=0;col<4;++col)
{
elements[row][col]=0.0;
}
}
}
public void multPointMatrix(Vec3 in, Vec3 out)
{
//in is a row-vector in this!!
//out = in * this;
out.elements[X] = in.elements[X] * elements[0][0] + in.elements[Y] * elements[1][0] + in.elements[Z] * elements[2][0] + /* in.w = 1 */ elements[3][0];
out.elements[Y] = in.elements[X] * elements[0][1] + in.elements[Y] * elements[1][1] + in.elements[Z] * elements[2][1] + /* in.w = 1 */ elements[3][1];
out.elements[Z] = in.elements[X] * elements[0][2] + in.elements[Y] * elements[1][2] + in.elements[Z] * elements[2][2] + /* in.w = 1 */ elements[3][2];
double w = in.elements[X] * elements[0][3] + in.elements[Y] * elements[1][3] + in.elements[Z] * elements[2][3] + /* in.w = 1 */ elements[3][3];
// normalize if w is different than 1 (convert from homogeneous to Cartesian coordinates)
if (w != 1) {
out.elements[X] /= w;
out.elements[Y] /= w;
out.elements[Z] /= w;
}
}
public void multMatrixMatrix(Matrix44 in, Matrix44 out)
{
for(int rvrow=0;rvrow<4;++rvrow)
{
for (int rvcol = 0; rvcol < 4; ++rvcol)
{
out.elements[rvrow][rvcol]=0;
for(int i=0;i<4;++i)
{
out.elements[rvrow][rvcol]+=elements[rvrow][i]*in.elements[i][rvcol];
}
}
}
}
@Override
public String toString()
{
return "Matrix44{" +
"elements=" + Arrays.toString(elements) +
'}';
}
public static void main(java.lang.String[] args) throws IOException
{
java.util.List<java.util.List<Vec3>> ll=new java.util.LinkedList();
java.util.List<Vec3> l=new java.util.LinkedList();
l.add(new Vec3(15,3,2));
l.add(new Vec3(15,3,8));
l.add(new Vec3(15,-3,8));
l.add(new Vec3(15,-3,2));
ll.add(l);
java.util.Random rand=new java.util.Random();
double maxx=80.0;
double maxy=80.0;
double maxz=40.0;
double maxwidth=18.0;
double maxheight=18.0;
int mode=0;
if(mode==0)
{
for (int i = 0; i < 80; ++i)
{
double x = rand.nextDouble() * (maxx - maxx * 0.5);
double y = rand.nextDouble() * (maxy - maxy * 0.5 - maxwidth / 2);
double z = rand.nextDouble() * maxz - (maxz - 10);
double width = rand.nextDouble() * (maxwidth - 2) + 2;
double height = rand.nextDouble() * (maxheight - 2) + 2;
l = new java.util.LinkedList();
l.add(new Vec3(x, y, z));
l.add(l.get(l.size() - 1).addAndNew(0, width, 0));
l.add(l.get(l.size() - 1).addAndNew(0, 0, height));
l.add(l.get(l.size() - 1).addAndNew(0, -width, 0));
ll.add(l);
}
}
else if (mode==1)
{
for (int i = 0; i < 80; ++i)
{
double x = rand.nextDouble() * maxx - maxx * 0.5;
double y = rand.nextDouble() * maxy - maxy * 0.5 - maxwidth / 2;
double z = rand.nextDouble() * maxz - (maxz - 10);
double width = rand.nextDouble() * (maxwidth - 2) + 2;
double height = rand.nextDouble() * (maxheight - 2) + 2;
l = new java.util.LinkedList();
l.add(new Vec3(x, y, z));
l.add(l.get(l.size() - 1).addAndNew(0, width, 0));
l.add(l.get(l.size() - 1).addAndNew(0, 0, height));
l.add(l.get(l.size() - 1).addAndNew(0, -width, 0));
ll.add(l);
}
}
else if (mode==2)
{
for (int i = 0; i < 40; ++i)
{
double x = rand.nextDouble() * maxx - maxx * 0.5;
double y = rand.nextDouble() * maxy - maxy * 0.5 - maxwidth / 2;
double z = rand.nextDouble() * maxz - (maxz - 10);
double width = rand.nextDouble() * (maxwidth - 2) + 2;
double height = rand.nextDouble() * (maxheight - 2) + 2;
l = new java.util.LinkedList();
l.add(new Vec3(x, y, z));
l.add(l.get(l.size() - 1).addAndNew(0, width, 0));
l.add(l.get(l.size() - 1).addAndNew(0, 0, height));
l.add(l.get(l.size() - 1).addAndNew(0, -width, 0));
ll.add(l);
}
for (int i = 0; i < 40; ++i)
{
double x = rand.nextDouble() * maxx - maxx * 0.5;
double y = rand.nextDouble() * maxy - maxy * 0.5 - maxwidth / 2;
double z = rand.nextDouble() * maxz - (maxz - 10);
double width = rand.nextDouble() * (maxwidth - 2) + 2;
double height = rand.nextDouble() * (maxheight - 2) + 2;
l = new java.util.LinkedList();
l.add(new Vec3(x, y, z));
l.add(l.get(l.size() - 1).addAndNew(width, 0, 0));
l.add(l.get(l.size() - 1).addAndNew(0, 0, height));
l.add(l.get(l.size() - 1).addAndNew(-width, 0, 0));
ll.add(l);
}
}
java.awt.image.BufferedImage bimg=new java.awt.image.BufferedImage(512,512, BufferedImage.TYPE_INT_ARGB);
Matrix44 proj=Matrix44.buildPerspectiveMatrix(120,0.1,100);
Matrix44 worldToCamera=Matrix44.buildAffineTranslateMatrix(0,0,-30);
Matrix44 scale=Matrix44.buildAffineScaleMatrix(bimg.getWidth()/2,bimg.getHeight()/2,0);
Matrix44 trans=Matrix44.buildAffineTranslateMatrix(bimg.getWidth()/2,bimg.getHeight()/2,0);
Matrix44 m1=new Matrix44();
Matrix44 m2=new Matrix44();
worldToCamera.multMatrixMatrix(proj,m1);
m1.multMatrixMatrix(scale,m2);
m2.multMatrixMatrix(trans,m1);
Vec3 vertCamera=new Vec3();
Vec3 projectedVert=new Vec3();
Vec3 scaled=new Vec3();
Vec3 translated=new Vec3();
Vec3 v1=new Vec3();
Vec3 v2=new Vec3();
java.awt.Color background= Color.DARK_GRAY;
java.awt.Graphics2D g2=bimg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2.setPaint(background);
g2.fillRect(0,0,bimg.getWidth(),bimg.getHeight());
int loop=0;
RandomColor randomColor=new RandomColor();
for(java.util.List<Vec3> lt:ll)
{
java.awt.Polygon polygon=new Polygon();
Vec3 origin=lt.get(0);
Matrix44 hin=Matrix44.buildAffineTranslateMatrix(-origin.elements[X],-origin.elements[Y],0);
Matrix44 rot=Matrix44.buildAffineRotateAroundZMatrix(rand.nextDouble()*360.0);
Matrix44 rueck=Matrix44.buildAffineTranslateMatrix(origin.elements[X],origin.elements[Y],0);
for(Vec3 vv:lt)
{
if(mode==0)
{
rot.multPointMatrix(vv, v1);
m1.multPointMatrix(v1, translated);
}
else
m1.multPointMatrix(vv, translated);
g2.setPaint(Color.BLUE);
polygon.addPoint((int)translated.toPoint2D().getX(),(int)translated.toPoint2D().getY());
++loop;
}
polygon.addPoint(polygon.xpoints[0],polygon.ypoints[0]);
java.awt.Color c=randomColor.next();
c=new Color(c.getRed(),c.getGreen(),c.getBlue(),180-rand.nextInt(100));
RadialGradientPaint p =
new RadialGradientPaint(new java.awt.geom.Point2D.Double(bimg.getWidth()/2,bimg.getHeight()/2), bimg.getWidth()/2, new float[]{0,1f}, new java.awt.Color[]{background,c});
g2.setPaint(p);
g2.fillPolygon(polygon);
}
g2.dispose();
javax.imageio.ImageIO.write(bimg,"png",new java.io.File("/tmp/render.png"));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment