{"id":408,"date":"2023-04-19T16:00:12","date_gmt":"2023-04-19T16:00:12","guid":{"rendered":"https:\/\/threeaces.co.uk\/insights\/?p=408"},"modified":"2023-08-01T15:53:29","modified_gmt":"2023-08-01T15:53:29","slug":"using-chat-gpt-to-create-a-three-js-composition","status":"publish","type":"post","link":"https:\/\/threeaces.co.uk\/insights\/creative-tech\/using-chat-gpt-to-create-a-three-js-composition\/","title":{"rendered":"Using Chat GPT to create a THREE.js composition"},"content":{"rendered":"\n<p>I wanted to try using Chat GPT to write code for me based on a simple starting prompt. I had already successfully done that for a very simple composition, now I wanted to try to get Chat GPT to do as much as the work as possible. The idea was to have one instance working as a coder &#8211; we\u2019ll call it Coder, and the other reviewing its output &#8211; we\u2019ll call it Assistant.<\/p>\n\n\n\n<p>The purple background text is my prompts, blue background text is Chat GPT&#8217;s answers.<\/p>\n\n\n\n<h2>Setup<\/h2>\n\n\n\n<p>I started by feeding Coder GPT a prompt describing our framework and platform, along with example code and type definition for a VisComp ( visual composition, our main building blocks, similar to Unity game objects ).<\/p>\n\n\n\n<p>I then gave it the following prompt:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p class=\"has-base-color has-vivid-purple-background-color has-text-color has-background\">Write the typedef and the code for a VisComp that:<\/p>\n\n\n\n<p class=\"has-base-color has-vivid-purple-background-color has-text-color has-background\">&#8211; creates a variable amount of objects using its &#8216;materials&#8217; and &#8216;geometries&#8217; inputs<\/p>\n\n\n\n<p class=\"has-base-color has-vivid-purple-background-color has-text-color has-background\">&#8211; positions the objects in space on the surface of a sphere of variable radius<\/p>\n\n\n\n<p class=\"has-base-color has-vivid-purple-background-color has-text-color has-background\">&#8211; animates each object along its own curve, which is procedurally generated and loops back onto itself<\/p>\n<\/blockquote>\n\n\n\n<p>The code it came up with seemed OK, but that wasn&#8217;t for to me to judge.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">\n<p>Here is the type definition and code for the VisComp as per your requirements:<\/p>\n\n\n\n<p>Example type definition:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">typescriptCopy code<code>type SphereSurfaceVisComp = {\n  materials: Material[];\n  geometries: Geometry[];\n  count: int;\n  radius: float;\n  \/**\n   * @meta {\"min\":0,\"max\":1}\n   *\/\n  curveTightness: float;\n};\n<\/code><\/pre>\n\n\n\n<p>Example VisComp code:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">javascriptCopy code<code>class SphereSurfaceVisComp extends VisComp {\n  start() {\n    super.start();\n    this.generateObjects();\n  }\n\n  generateObjects() {\n    if (this.objects) {\n      for (let obj of this.objects) {\n        obj.material.dispose();\n        obj.geometry.dispose();\n        this.cont3D.remove(obj);\n      }\n    }\n\n    this.objects = [];\n\n    const materials = this.inputs.get('materials');\n    const geometries = this.inputs.get('geometries');\n    const count = this.inputs.getObject('count');\n    const radius = this.inputs.get('radius');\n    const curveTightness = this.inputs.get('curveTightness');\n\n    for (let i = 0; i &lt; count; i++) {\n      const mat = materials[i % materials.length];\n      const geom = geometries[i % geometries.length];\n      const obj = new THREE.Mesh(geom, mat);\n      const phi = Math.random() * Math.PI * 2;\n      const theta = Math.acos(2 * Math.random() - 1);\n      obj.position.set(\n        radius * Math.sin(theta) * Math.cos(phi),\n        radius * Math.sin(theta) * Math.sin(phi),\n        radius * Math.cos(theta)\n      );\n      obj.curveTightness = curveTightness;\n      obj.curveOffset = Math.random() * Math.PI * 2;\n      obj.curveSpeed = Math.random() * 0.01 + 0.005;\n      this.cont3D.add(obj);\n      this.objects.push(obj);\n    }\n  }\n\n  inputChanged(event) {\n    switch (event.type) {\n      case 'materials':\n      case 'geometries':\n      case 'radius':\n      case 'curveTightness':\n        this.generateObjects();\n    }\n  }\n\n  dispose() {\n    if (this.objects) {\n      for (let obj of this.objects) {\n        obj.material.dispose();\n        obj.geometry.dispose();\n        this.cont3D.remove(obj);\n      }\n    }\n    super.dispose();\n  }\n\n  update(dt) {\n    super.update(dt);\n    for (let obj of this.objects) {\n      const t = (Date.now() * obj.curveSpeed + obj.curveOffset) % (Math.PI * 2);\n      const newPosition = new THREE.Vector3(\n        obj.position.x + Math.cos(t) * obj.curveTightness,\n        obj.position.y + Math.sin(t) * obj.curveTightness,\n        obj.position.z + Math.cos(t) * obj.curveTightness\n      );\n      newPosition.normalize().multiplyScalar(this.inputs.get('radius'));\n      obj.position.copy(newPosition);\n    }\n  }\n}\n<\/code><\/pre>\n\n\n\n<p>This VisComp creates a specified number of objects using the provided materials and geometries, positions them on the surface of a sphere with a variable radius, and animates each object along its own looping, procedurally generated curve.<\/p>\n<\/blockquote>\n\n\n\n<p>I started another Chat GPT chat for our Assistant:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p class=\"has-base-color has-vivid-purple-background-color has-text-color has-background\">You are Assistant GPT. You will be working in tandem with another instance of Chat GPT, which will be writing the code from my initial prompt. You will review its output and suggest how to improve it, and also provide it with any errors that happen when running the code.<\/p>\n\n\n\n<p class=\"has-base-color has-vivid-purple-background-color has-text-color has-background\">Here is the starting prompt it has received:<\/p>\n\n\n\n<p class=\"has-base-color has-vivid-purple-background-color has-text-color has-background\">[ here I pasted the prompt I gave Coder ]<\/p>\n\n\n\n<p class=\"has-base-color has-vivid-purple-background-color has-text-color has-background\">You will now review its code and suggest improvements.<\/p>\n\n\n\n<p class=\"has-base-color has-vivid-purple-background-color has-text-color has-background\">Here is the typedef and code it has generated:<\/p>\n\n\n\n<p class=\"has-base-color has-vivid-purple-background-color has-text-color has-background\">[ here i pasted the typedef and code ]<\/p>\n<\/blockquote>\n\n\n\n<p>I got a decent answer, with a few suggestions on improvements. Assistant also rewrote the code for me, however the code was truncated.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">The generated code appears to be a VisComp class that generates objects on the surface of a sphere with a specified radius, materials, and geometries. The objects move along curved paths based on the curveTightness parameter. Overall, the code is well-structured and mostly correct. However, there are a few improvements and fixes that can be made:<\/p>\n\n\n\n<ol>\n<li>In the <code>generateObjects()<\/code> method, you should use <code>this.inputs.getObject()<\/code> instead of <code>this.inputs.get()<\/code> for the count parameter. This is because <code>getObject()<\/code> is used for accessing parameters according to the initial prompt.<\/li>\n\n\n\n<li>In the <code>inputChanged()<\/code> method, you should regenerate the objects only if there is a change in the materials, geometries, or count. The radius and curveTightness changes should be handled separately, as they don&#8217;t require the complete regeneration of objects.<\/li>\n<\/ol>\n\n\n\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">Here is the updated code:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">javascriptCopy code<code>class SphereSurfaceVisComp extends VisComp {\n  start() {\n    super.start();\n    this.generateObjects();\n  }\n\n  generateObjects() {\n    if (this.objects) {\n      for (let obj of this.objects) {\n        obj.material.dispose();\n        obj.geometry.dispose();\n        this.cont3D.remove(obj);\n      }\n    }\n\n    this.objects = [];\n\n    const materials = this.inputs.get('materials');\n    const geometries = this.inputs.get('geometries');\n    const count = this.inputs.getObject('count');\n    const radius = this.inputs.get('radius');\n    const curveTightness = this.inputs.get('curveTightness');\n\n    for (let i = 0; i &lt; count; i++) {\n      const mat = materials[i % materials.length];\n      const geom = geometries[i % geometries.length];\n      const obj = new THREE.Mesh(geom, mat);\n      const phi = Math.random() * Math.PI * 2;\n      const theta = Math.acos(2 * Math.random() - 1);\n      obj.position.set(\n        radius * Math.sin(theta) * Math.cos(phi),\n        radius * Math.sin(theta) * Math.sin(phi),\n        radius * Math.cos(theta)\n      );\n      obj.curveTightness = curveTightness;\n      obj.curveOffset = Math.random() * Math.PI * 2;\n      obj.curveSpeed = Math.random() * 0.01 + 0.005;\n      this.cont3D.add(obj);\n      this.objects.push(obj);\n    }\n  }\n\n  inputChanged(event) {\n    switch (event.type) {\n      case 'materials':\n      case 'geometries':\n      case 'count':\n        this.generateObjects();\n        break;\n      case 'radius':\n      case 'curveTightness':\n        this.updateObjectParameters();\n        break;\n    }\n  }\n\n  updateObjectParameters() {\n    const radius = this.inputs.get('radius');\n    const curveTightness = this.inputs.get('curveTightness');\n    for (let obj of this.objects) {\n      obj.curveTightness = curveTightness;\n    }\n  }\n\n  dispose() {\n    if (this.objects) {\n      for (let obj of this.objects) {\n        obj.material.dispose();\n        obj.geometry.dispose();\n        this.cont3D.remove(obj);\n      }\n    }\n    super.dispose();\n  }\n\n  update(dt) {\n    super.update(dt);\n    const radius = this.inputs.get('radius');\n    for (let obj of this.objects) {\n      const t = (Date.now() * obj.curveSpeed + obj.curveOffset) % (Math.PI * 2);\n      const newPosition = new THREE.Vector3(\n        obj.position.x + Math.cos(t) * obj.curveTightness,\n        obj.position.y + Math.sin(t) * obj.curveTightness,\n        obj.position<\/code><\/pre>\n<\/blockquote>\n\n\n\n<p>So I just pasted Assistant\u2019s output back into the chat with Coder without any extra prompting. And Coder finished the code from where Assistant had stopped.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">.z + Math.cos(t) * obj.curveTightness ); newPosition.normalize().multiplyScalar(radius); obj.position.copy(newPosition); } } }<\/p>\n\n\n\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">This updated VisComp class now uses <code>this.inputs.getObject()<\/code> for accessing the <code>count<\/code> parameter and handles changes to the <code>radius<\/code> and <code>curveTightness<\/code> parameters separately, without regenerating the objects entirely. Instead, the <code>updateObjectParameters()<\/code> method is called, which updates the necessary parameters for the existing objects in the scene.<\/p>\n<\/blockquote>\n\n\n\n<p>From what I\u2019ve seen, when Chat GPT completes code snippets, it loses the code highlighting, which is a bit inconvenient.<\/p>\n\n\n\n<p>I pasted the code and typedef into our CMS\u2019s editor app, selected a few geometries and materials, and arbitrary values for the count and curveTightness inputs.<\/p>\n\n\n\n<p>The code didn;t run, as an error was thrown from somewhere inside the THREE.js library. I checked the GPT generated code and easily\u00a0figured out where the error was coming from. But I wanted to see if GPT would be able to identify it.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p class=\"has-base-color has-vivid-purple-background-color has-text-color has-background\">ee.min.js:6 Uncaught (in promise) TypeError: Cannot convert undefined or null to object at Function.keys (&lt;anonymous&gt;) at Ki.updateMorphTargets (three.min.js:6:106109) at new Ki (three.min.js:6:105732) at SphereSurfaceVisComp.generateObjects (9d8e385b-ca6d-45aa-8ed2-674e27798ee9:27:19) at SphereSurfaceVisComp.start (9d8e385b-ca6d-45aa-8ed2-674e27798ee9:4:10) at SceneSingle.js:332:20 at Generator.next (&lt;anonymous&gt;) at s (asyncToGenerator.js:3:20) at o (asyncToGenerator.js:25:9) at asyncToGenerator.js:32:7 u<\/p>\n<\/blockquote>\n\n\n\n<p><\/p>\n\n\n\n<p>Its solution didn\u2019t work, but it was an OK try.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">It seems that you&#8217;re encountering an error related to the THREE.js library, specifically in the <code>updateMorphTargets<\/code> function. This error typically occurs when the geometry is undefined or null. To resolve this issue, please ensure that you have properly loaded and assigned the geometries before creating the mesh in the <code>generateObjects()<\/code> method.<\/p>\n\n\n\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">Here&#8217;s the updated <code>generateObjects()<\/code> method with added checks for valid geometries and materials:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">javascriptCopy code<code>generateObjects() {\n  if (this.objects) {\n    for (let obj of this.objects) {\n      obj.material.dispose();\n      obj.geometry.dispose();\n      this.cont3D.remove(obj);\n    }\n  }\n\n  this.objects = [];\n\n  const materials = this.inputs.get('materials');\n  const geometries = this.inputs.get('geometries');\n  const count = this.inputs.getObject('count');\n  const radius = this.inputs.get('radius');\n  const curveTightness = this.inputs.get('curveTightness');\n\n  if (!materials || !geometries || materials.length === 0 || geometries.length === 0) {\n    return;\n  }\n\n  for (let i = 0; i &lt; count; i++) {\n    const mat = materials[i % materials.length];\n    const geom = geometries[i % geometries.length];\n\n    if (!mat || !geom) {\n      continue;\n    }\n\n    const obj = new THREE.Mesh(geom, mat);\n    const phi = Math.random() * Math.PI * 2;\n    const theta = Math.acos(2 * Math.random() - 1);\n    obj.position.set(\n      radius * Math.sin(theta) * Math.cos(phi),\n      radius * Math.sin(theta) * Math.sin(phi),\n      radius * Math.cos(theta)\n    );\n    obj.curveTightness = curveTightness;\n    obj.curveOffset = Math.random() * Math.PI * 2;\n    obj.curveSpeed = Math.random() * 0.01 + 0.005;\n    this.cont3D.add(obj);\n    this.objects.push(obj);\n  }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">This updated <code>generateObjects()<\/code> method checks if the <code>materials<\/code> and <code>geometries<\/code> arrays are not null and not empty, and checks if the individual <code>mat<\/code> and <code>geom<\/code> elements are not null before creating the mesh. If the geometry or material is not valid, the loop will continue without creating the object. Make sure your assets are properly loaded before creating the VisComp.<\/p>\n<\/blockquote>\n\n\n\n<p>The error in the code was caused by my initial prompt, which used the wrong XRC framework method, so GPT was working from an incorrect example\u2026&nbsp;<\/p>\n\n\n\n<p>I informed GPT about it and told it I would fix the code myself.<\/p>\n\n\n\n<p>Having fixed the code, the composition was now running, and looking fairly decent. Have a look:<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/threeaces.co.uk\/insights\/wp-content\/uploads\/2023\/04\/GPTVisComp1.mp4\"><\/video><\/figure>\n\n\n\n<p>There is just one issue: when I increase the radius like at the end of the video, the objects all end up on the same plane which looks a bit boring. Looking at the code, I\u2019m not sure why this is happening. Let\u2019s see if Coder can figure it out faster than me.<\/p>\n\n\n\n<p>Let\u2019s prompt it:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p class=\"has-base-color has-vivid-purple-background-color has-text-color has-background\">When I change the radius parameter, in some cases all the objects end up positioned on a circle instead of a sphere. Can you fix that please?<\/p>\n<\/blockquote>\n\n\n\n<p>Coder seems confident in its response, which absolutely doesn\u2019t fix it.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">I apologize for the confusion. The issue you&#8217;re experiencing is caused by the way the objects are updated in the <code>update()<\/code> method. The current implementation does not account for the change in the radius when updating the position of the objects.<\/p>\n\n\n\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">Here&#8217;s the modified <code>update()<\/code> method that should resolve the issue:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">javascriptCopy code<code>update(dt) {\n  super.update(dt);\n  const radius = this.inputs.get('radius');\n  for (let obj of this.objects) {\n    const t = (Date.now() * obj.curveSpeed + obj.curveOffset) % (Math.PI * 2);\n    const newPosition = obj.position.clone();\n    newPosition.add(new THREE.Vector3(\n      Math.cos(t) * obj.curveTightness,\n      Math.sin(t) * obj.curveTightness,\n      Math.cos(t) * obj.curveTightness\n    ));\n    newPosition.normalize().multiplyScalar(radius);\n    obj.position.copy(newPosition);\n  }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">In this updated <code>update()<\/code> method, we first clone the object&#8217;s current position and then add the new movement vector to it. This approach ensures that the object remains on the sphere&#8217;s surface even when the radius is changed.<\/p>\n<\/blockquote>\n\n\n\n<p>Let\u2019s try again:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p class=\"has-base-color has-vivid-purple-background-color has-text-color has-background\">The issue is still there.<\/p>\n<\/blockquote>\n\n\n\n<p>As usual, Coder apologises for the confusion, before offering a solution that sounds OK, but actually isn\u2019t.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">I apologize for the confusion. I realize now that the previous approach still had some issues. I have re-evaluated the problem and created a new solution that should resolve it. This time, I am using spherical coordinates to update the object&#8217;s position according to the new radius while maintaining their relative distribution on the sphere.<\/p>\n\n\n\n<p>Here&#8217;s the modified <code>update()<\/code> method:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">javascriptCopy code<code>update(dt) {\n  super.update(dt);\n  const radius = this.inputs.get('radius');\n  for (let obj of this.objects) {\n    const t = (Date.now() * obj.curveSpeed + obj.curveOffset) % (Math.PI * 2);\n    const spherical = new THREE.Spherical();\n    spherical.setFromVector3(obj.position);\n    spherical.radius = radius;\n    spherical.phi += Math.cos(t) * obj.curveTightness * dt;\n    spherical.theta += Math.sin(t) * obj.curveTightness * dt;\n    obj.position.setFromSpherical(spherical);\n  }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">In this updated <code>update()<\/code> method, we convert the object&#8217;s position to spherical coordinates using <code>THREE.Spherical<\/code>. We update the <code>radius<\/code>, <code>phi<\/code>, and <code>theta<\/code> values of the spherical coordinates and then convert them back to Cartesian coordinates, which are applied to the object&#8217;s position. This ensures that the objects remain on the sphere&#8217;s surface when the radius is changed, and they move along their own curve.<\/p>\n<\/blockquote>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p class=\"has-base-color has-vivid-purple-background-color has-text-color has-background\">Still not fixed. When I change the radius, the objects now are all in the same position.<\/p>\n<\/blockquote>\n\n\n\n<p>As it starts typing, I get the feeling it\u2019s not going to manage it. It starts by rewriting the update() function so that it looks like one of the previous incorrect ones. But surprise! It does identify the problem and\u00a0 realises it also needs to update the generateObjects function. The issue is now solved.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">I apologize for the confusion in my previous responses. I understand the issue now and have revised the solution accordingly. The updated approach maintains each object&#8217;s relative position on the sphere when the radius is changed.<\/p>\n\n\n\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">Here&#8217;s the modified <code>update()<\/code> method:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">javascriptCopy code<code>update(dt) {\n  super.update(dt);\n  const radius = this.inputs.get('radius');\n  for (let obj of this.objects) {\n    const t = (Date.now() * obj.curveSpeed + obj.curveOffset) % (Math.PI * 2);\n\n    const newPosition = obj.initialPosition.clone();\n    newPosition.add(new THREE.Vector3(\n      Math.cos(t) * obj.curveTightness,\n      Math.sin(t) * obj.curveTightness,\n      Math.cos(t) * obj.curveTightness\n    ));\n    newPosition.normalize().multiplyScalar(radius);\n    obj.position.copy(newPosition);\n  }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">You should also store the initial position of each object when you generate them in the <code>generateObjects()<\/code> method:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">javascriptCopy code<code>\/\/ ...\nconst obj = new THREE.Mesh(geom, mat);\nconst phi = Math.random() * Math.PI * 2;\nconst theta = Math.acos(2 * Math.random() - 1);\nobj.position.set(\n  radius * Math.sin(theta) * Math.cos(phi),\n  radius * Math.sin(theta) * Math.sin(phi),\n  radius * Math.cos(theta)\n);\nobj.initialPosition = obj.position.clone();\n\/\/ ...\n<\/code><\/pre>\n\n\n\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">In this updated <code>update()<\/code> method, we use the object&#8217;s initial position as a base and then add the new movement vector to it. This approach ensures that the object remains on the sphere&#8217;s surface even when the radius is changed. By storing and using the initial position of each object, we avoid the issue of all objects converging to the same position.<\/p>\n<\/blockquote>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/threeaces.co.uk\/insights\/wp-content\/uploads\/2023\/04\/GPTVisComp2.mp4\"><\/video><\/figure>\n\n\n\n<p>Chat GPT has successfully coded my brief. It doesn\u2019t look great though, and I think that\u2019s mainly due to my selection of materials and geometries &#8211; I picked the first things at hand.<\/p>\n\n\n\n<p>I can see one thing we can add to the code to make it look better: some rotation from the objects would be nice. The object\u2019s speeds could also vary through time.<\/p>\n\n\n\n<p>And in terms of geometries \/ materials, I could do with some kind of concept to make it more interesting. I can see this having a good effect if we were to use shader materials for the objects, and the object\u2019s speed and \/ or position had an effect on the shaders, eg faster objects tending towards red and slower ones towards blue ( some kind of budget Dopppler effect ).<\/p>\n\n\n\n<p>But let\u2019s see if Chat GPT can offer any creative input. In order to make sure Coder GPT stays focused on the task (we have to be mindful of its token limitations), I\u2019ll ask our Assistant to give some suggestions<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p class=\"has-base-color has-vivid-purple-background-color has-text-color has-background\">The coder instance has finished coding this. Can you suggest ways in which to make this more interesting visually, both in terms of additional features in the code, and selection of geometry, materials, postprocessing and background?<\/p>\n<\/blockquote>\n\n\n\n<p>Surprisingly, Assistant GPT doesn\u2019t tell pull out the standard \u2018As an AI language model I can&#8217;t be creative\u2019 spiel. It gives me a list of things, which aren\u2019t that useful &#8211; I want it to be more specific and tell me exactly what I need to use. I can tell by myself that using different geometries and materials should make it look better, what I want to know is what geometries and materials I should use.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">Certainly! Here are some suggestions to make the visuals more interesting:<\/p>\n\n\n\n<ol>\n<li>Geometry and materials:Instead of using simple geometries, you can use more complex and interesting geometries like a TorusKnotGeometry or an IcosahedronGeometry. You can also mix different types of geometries for a more diverse visual composition.For materials, you can use a variety of materials like MeshStandardMaterial, MeshPhongMaterial, or MeshToonMaterial. Consider using textures and environment maps to create more realistic and visually appealing materials. Also, consider using vertex and fragment shaders to create custom materials.<\/li>\n\n\n\n<li>Postprocessing:Apply postprocessing effects to enhance the visuals. Some interesting postprocessing effects available in THREE.js are:\n<ul>\n<li>BloomEffect<\/li>\n\n\n\n<li>DepthOfFieldEffect<\/li>\n\n\n\n<li>FilmEffect<\/li>\n\n\n\n<li>VignetteEffect<\/li>\n\n\n\n<li>ChromaticAberrationEffect<\/li>\n\n\n\n<li>GodRaysEffect<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Background:Instead of using a solid color background, consider using a Skybox or a dynamically generated procedural background using Perlin noise or a custom fragment shader. This will make the scene feel more immersive and engaging.<\/li>\n\n\n\n<li>Additional features in the code:\n<ul>\n<li>Add interactivity: Make the objects respond to user input, such as mouse\/touch events, by changing their position, rotation, or scale.<\/li>\n\n\n\n<li>Animate properties: Animate the colors, materials, or geometries of the objects to create a more dynamic scene.<\/li>\n\n\n\n<li>Add lights: Include various types of lights like PointLight, DirectionalLight, or SpotLight to create a more visually interesting scene. Consider using shadows for added depth.<\/li>\n\n\n\n<li>Use a camera controller: Implement a camera controller like OrbitControls or FlyControls to allow users to navigate the scene and explore the objects from different perspectives.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Advanced features:\n<ul>\n<li>Physically based rendering (PBR): Use PBR materials like MeshStandardMaterial or MeshPhysicalMaterial to achieve more realistic lighting and reflections.<\/li>\n\n\n\n<li>Reflections and refractions: Add environment maps to create reflective or refractive materials, making the scene more visually rich.<\/li>\n\n\n\n<li>Particles: Add a particle system to create effects like smoke, fire, or sparkles, which can add more life to the scene.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">By combining these suggestions, you can create a more visually engaging and interesting scene in the XRC framework.<\/p>\n<\/blockquote>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p class=\"has-base-color has-vivid-purple-background-color has-text-color has-background\">using your suggestions, can you select some arbitrary options for this composition?<\/p>\n<\/blockquote>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">Certainly! Here&#8217;s a combination of options to create an interesting visual composition:<\/p>\n\n\n\n<ol>\n<li>Geometry and materials:Geometries:<ul><li>THREE.TorusKnotGeometry<\/li><li>THREE.IcosahedronGeometry<\/li><li>THREE.BoxGeometry<\/li><\/ul>Materials:\n<ul>\n<li>MeshStandardMaterial with a texture map and roughness\/metalness maps<\/li>\n\n\n\n<li>MeshPhongMaterial with a texture map and specular map<\/li>\n\n\n\n<li>MeshToonMaterial with a gradient map<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Postprocessing:Apply the following postprocessing effects:\n<ul>\n<li>BloomEffect: to create a glow around brighter areas<\/li>\n\n\n\n<li>VignetteEffect: to softly darken the corners of the screen<\/li>\n\n\n\n<li>ChromaticAberrationEffect: to simulate the lens distortion<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Background:Use a Skybox with 6 textures to create an environment map that represents a space scene or a beautiful landscape.<\/li>\n\n\n\n<li>Additional features in the code:\n<ul>\n<li>Interactivity: Change the rotation of objects when the user clicks on them.<\/li>\n\n\n\n<li>Animate properties: Animate the colors or emissive properties of the materials over time.<\/li>\n\n\n\n<li>Add lights: Add a PointLight with a slight color tint and a DirectionalLight for general scene illumination. Enable shadows for the DirectionalLight.<\/li>\n\n\n\n<li>Use a camera controller: Implement OrbitControls to allow users to navigate around the scene.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Advanced features:\n<ul>\n<li>Physically based rendering (PBR): Use MeshStandardMaterial for the TorusKnotGeometry and IcosahedronGeometry objects.<\/li>\n\n\n\n<li>Reflections: Add an environment map to the MeshStandardMaterial for the TorusKnotGeometry object to create a reflective surface.<\/li>\n\n\n\n<li>Particles: Add a particle system around the objects to simulate floating dust particles in the scene.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p class=\"has-base-color has-vivid-cyan-blue-background-color has-text-color has-background\">By implementing these options, you&#8217;ll create a visually engaging composition in the XRC framework with an interesting combination of geometries, materials, effects, and features.<\/p>\n<\/blockquote>\n\n\n\n<p>Some of these are OK, the postprocessing and additional code features shouldn;t look too bad. Not too keen on the materials and background selection.<\/p>\n\n\n\n<p>As Chat GPT does;t have access to our CMS (for now..), I can\u2019t get make it decide which assets to use.&nbsp;<\/p>\n\n\n\n<p>Since I\u2019m planning on being as lazy as possible, in part 2 of this we\u2019ll rework the code to make it more procedural &#8211; getting rid of the geometry and material inputs. Chat GPT will generate them by code, and maybe also add us an abstract procedural skybox. I want AI to write my code and make it look good, so I can have a sandwich and a beer.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wanted to try using Chat GPT to write code for me based on a simple starting prompt. I had already successfully done that for a very simple composition, now I wanted to try to get Chat GPT to do as much as the work as possible. The idea was to have one instance working [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[5],"tags":[],"_links":{"self":[{"href":"https:\/\/threeaces.co.uk\/insights\/wp-json\/wp\/v2\/posts\/408"}],"collection":[{"href":"https:\/\/threeaces.co.uk\/insights\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/threeaces.co.uk\/insights\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/threeaces.co.uk\/insights\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/threeaces.co.uk\/insights\/wp-json\/wp\/v2\/comments?post=408"}],"version-history":[{"count":11,"href":"https:\/\/threeaces.co.uk\/insights\/wp-json\/wp\/v2\/posts\/408\/revisions"}],"predecessor-version":[{"id":421,"href":"https:\/\/threeaces.co.uk\/insights\/wp-json\/wp\/v2\/posts\/408\/revisions\/421"}],"wp:attachment":[{"href":"https:\/\/threeaces.co.uk\/insights\/wp-json\/wp\/v2\/media?parent=408"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/threeaces.co.uk\/insights\/wp-json\/wp\/v2\/categories?post=408"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/threeaces.co.uk\/insights\/wp-json\/wp\/v2\/tags?post=408"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}