https://ai-art-gallery.glitch.me
If you've been on social media throughout the last few months, chances are you've seen a plethora of artwork, written content, memes and more - created not by a human, but by an AI. Whilst software and new machine-learning AI systems such as DALL-E 2 and Midjourney have recently become the latest creative craze online, there has been little discussion as to the legal questions surrounding AI-generated content. It may seem a bit surreal or dystopian for some, but there is now a whole new universe of questions to be raised regarding intellectual property and AI.
As much machine-learning software utilises a database of images collated from other artists. Is it stealing, copying, or inspiration if you utilize someone else's artwork and artificial intelligence to create your own? The largest issue still is: Who owns AI-generated art once it has been produced?
My initial critical thinking about AI-Generated art is about the copyright, is it belongs to the artist(user)/developer/company/AI? In other words, what do people or organizations think about AI-generated art? Do arts must have to be created by people?
Combining Three.js, Socket.IO, MongoDB to create a simple AI-Generated art gallery website to invite people who haven’t used AI-generated art before in order to raise people’s awareness of AI copyright thinking.
- Create the cover page background using Three.js, users can move their mouse to control the point light. Using Socket.IO to allow multiple users to join in and create more point lights.
- The gallery section is the place to store the image data people uploaded(MongoDB).
- Popup window will show a warning and copyright message which is randomly generated by the algorithm when users click the upload button.
#gallery {
line-height:0;
-webkit-column-count:4; /* split it into 5 columns */
-webkit-column-gap:16px; /* give it a 5px gap between columns */
-moz-column-count:4;
-moz-column-gap:16px;
column-count:4;
column-gap:16px;
}
#gallery img {
width: 100%;
height: auto;
margin-bottom:5px; /* to match column gap */
filter: grayscale(100%);
transition: filter 1s;
}
#gallery img:hover {
filter:none;
}
@media (max-width: 1200px) {
#gallery {
-moz-column-count: 3;
-webkit-column-count: 3;
column-count: 3;
}
}
@media (max-width: 1000px) {
#gallery {
-moz-column-count: 2;
-webkit-column-count: 2;
column-count: 2;
}
}
@media (max-width: 800px) {
#gallery {
-moz-column-count: 1;
-webkit-column-count: 1;
column-count: 1;
}
}
@media (max-width: 400px) {
#gallery {
-moz-column-count: 1;
-webkit-column-count: 1;
column-count: 1;
}
}
- Use the mouse to control the point light position in Three.js. I created a function at the first time, but found it couldn't work when I tried to use Socket.IO to send data to the server, so I create a class to not only contains mouseMove function but also create a new random color point light as well. (Special thanks to Brian)
class userLight {
constructor(_scene, _camera) {
this.scene = _scene
this.position = new THREE.Vector3()
this.mouse = new THREE.Vector2()
this.camera = _camera
this.pointLight = new THREE.PointLight(clientColor, 1, 5)
this.pointLight.position.set(0, 0, 0);
this.pointLight.castShadow = true;
this.pointLight.shadow.bias = 0.0001;
this.pointLight.mapSizeWidth = 1024; // Shadow Quality
this.pointLight.mapSizeHeight = 1024; // Shadow Quality
this.trigger = true
}
create() {
if (this.trigger) {
//this.mesh.add(new THREE.Mesh(this.geometry, this.material))
this.scene.add(this.pointLight)
}
this.trigger = false
}
move(_position) {
let vector = new THREE.Vector3(_position.x, _position.y, 0.5)
vector.unproject(this.camera)
let dir = vector.sub(this.camera.position).normalize()
let distance = -this.camera.position.z / dir.z
let pos = this.camera.position.clone().add(dir.multiplyScalar(distance))
this.pointLight.position.copy(pos)
}
}
- Add a point light once a user connects to the server, and remove light when they disconnect. I add the ID to every specific user, and emit data when io.on
let users = [];
socket.on('dataAll', function (data) {
for (let i = 0; i < users.length; i++) {
if (data.id == users[i].id) {
users[i].object.move(data.pos)
}
}
})
socket.on('user', function (data) {
let u = new userLight(scene, camera)
let user = {
id: data,
object: u,
}
users.push(user)
for (let i = 0; i < users.length; i++) {
users[i].object.create()
}
})
socket.on('userLeft', function (id) {
for (let i = 0; i < users.length; i++) {
if (id == users[i].id) {
scene.remove(users[i].object.mesh)
}
}
})
The Socket.IO code in index.js file is like this
io.on('connection', function(socket) {
console.log("We have a new client: " + socket.id);
io.emit('user', socket.id)
//Listen for a message named 'msg' from this client
socket.on('data', function(data) {
//Data can be numbers, strings, objects
console.log("Received a 'data' event");
console.log(data);
//add id to user
let obj = {
pos: data,
id: socket.id,
}
});
//Listen for this client to disconnect
socket.on('disconnect', function() {
console.log("A client has disconnected: " + socket.id);
io.emit('userLeft', socket.id)
});
});
- Use gsap to create the animation when the model is successfully loaded.
let objMaterial = new THREE.MeshPhongMaterial({ // Required For Shadows
color: 0x888888,
specular: 0x000000,
shininess: 60,
});
//obj
let objLoader = new THREE.OBJLoader();
//new group
let group = new THREE.Group();
//objLoader.setMaterials(cubeMaterial);
objLoader.setPath('assets/');
objLoader.load('OR.obj', function (object) {
object.traverse(function (child) {
if (child instanceof THREE.Mesh) {
child.material = objMaterial;
}
});
object.scale.set(0, 0, 0);
object.rotation.set(Math.PI / 3, Math.PI / 3, Math.PI / 3);
group.add(object);
object.position.y = -13;
scene.add(group);
doAnimation();
function doAnimation() {
gsap.to(object.rotation, {
x: 0,
y: 0,
z: 0,
duration: 1,
paused: true
}).play()
gsap.to(object.scale, {
x: 1,
y: 1,
z: 1,
duration: 3,
paused: true
}).play()
}
});
- In Upload section, the upload button will be disabled unless users select file from their computer, and popup window will then show up when people click the upload button.
inputFile.addEventListener('change', function () {
let image = this.files[0]
if (image.size < 2000000) {
let reader = new FileReader();
upload.disabled = false;
reader.onload = () => {
let allImg = imgArea.querySelectorAll('img');
allImg.forEach(item => item.remove());
let imgUrl = reader.result;
let img = document.createElement('img');
img.src = imgUrl;
imgArea.appendChild(img);
imgArea.classList.add('active');
imgArea.dataset.img = image.name;
};
reader.readAsDataURL(image);
} else {
alert("Image size more than 2MB");
}
})
upload.addEventListener('click', function () {
document.querySelector('h2').remove();
upload.disabled = true;
document.getElementById("popup").classList.toggle("active");
//console.log("2")
imgArea.querySelectorAll('img').forEach(item => item.remove());
let word = ['You', 'Developers', 'Source Artists', 'AI', 'Software Companies'];
let copyright = word[Math.floor(Math.random() * word.length)];
//alert('Copyright' + copyright);
let cp = document.createElement('h2');
cp.innerHTML = "Copyright " + "Ⓒ " + copyright;
newCp.appendChild(cp);
//console.log(cp);
});
- Found MongoDB can’t deploy on glitch, so I deleted all the database code:) And also because I couldn't convert image to json data.
-
Store image in MongoDB, maybe will use Google Drive to store the image and generate link and use MongoDB to store the drive link.
-
Rotate camera/3D models position to have a different perspective when users go into other section.