fixed all the things
e3aa5a9a
4 file(s) · +103 −186
| 3 | 3 | publishDate: "18 May 2022" |
|
| 4 | 4 | description: "Learn how to scan and mint real life objects on Solana" |
|
| 5 | 5 | tags: ["web3", "nfts", "tutorials"] |
|
| 6 | + | ogImage: "https://miro.medium.com/v2/resize:fit:4800/format:webp/1*5vzpNGiQSZqe1EX6ghDINg.png" |
|
| 6 | 7 | --- |
|
| 8 | + | ||
| 9 | + | import { Image } from "@astrojs/image/components"; |
|
| 7 | 10 | ||
| 8 | 11 | The growth and evolution of NFTs has come a long way from the early days. Some of the early NFT projects were simple .png files or a link to a YouTube video, but now they are an entire industry that consumes brand, utility, even augmented reality. Metaverses, 3D objects, and other virtual reality experiences are all the rage, and I firmly believe we will see more of this in the near future. |
|
| 9 | 12 | ||
| 27 | 30 | ||
| 28 | 31 | With the video below you can get glimpse of how the LiDAR scanner maps over surfaces. Taking it real slow and covering every angle really helps with scanning environments. |
|
| 29 | 32 | ||
| 30 | - | >>INSERT VIMEO |
|
| 33 | + | <div style="padding:216.22% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/703877466?h=9659ba4952" style="position:absolute;top:0;left:0;width:100%;height:100%;" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe></div><script src="https://player.vimeo.com/api/player.js"></script> |
|
| 31 | 34 | ||
| 32 | 35 | After you’re done scanning there will be a processing step that will take all the data and map it into a 3D environment! |
|
| 33 | 36 | ||
| 34 | - | >>INSERT VIMEO |
|
| 37 | + | <div style="padding:216.22% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/703880632?h=52b5f574b7" style="position:absolute;top:0;left:0;width:100%;height:100%;" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe></div><script src="https://player.vimeo.com/api/player.js"></script> |
|
| 35 | 38 | ||
| 36 | 39 | Once it’s processed you can go ahead and view the 3D model/environment! Polycam really is first class; you can create videos, you can view the model in Augmented Reality, it just has so many awesome features! My model isn’t the cleanest since I have so many small detailed objects on my desk, but for something a bit simpler this feature is amazing. |
|
| 37 | 40 | ||
| 38 | - | >>INSERT VIMEO |
|
| 41 | + | <div style="padding:216.22% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/703884780?h=de95c5de7a" style="position:absolute;top:0;left:0;width:100%;height:100%;" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe></div><script src="https://player.vimeo.com/api/player.js"></script> |
|
| 39 | 42 | ||
| 40 | 43 | Now that we got our model, we can upload it to the cloud and look at it through our web browser! Just click on the little cloud icon on the top of the screen when viewing your model and it will be uploaded to your cloud storage with Polycam. |
|
| 41 | 44 | ||
| 42 | 45 | Once viewing it in the web browser, we can download the model by clicking “export.” |
|
| 43 | 46 | ||
| 44 | - | >>SCREENSHOT |
|
| 47 | + | <Image |
|
| 48 | + | src="https://miro.medium.com/v2/resize:fit:4800/format:webp/1*Olex5OAd3sMaugwF_iWGig.png" |
|
| 49 | + | alt="screenshot of room capture" |
|
| 50 | + | width={1920} |
|
| 51 | + | aspectRatio={16/9} |
|
| 52 | + | /> |
|
| 45 | 53 | ||
| 46 | 54 | From there we want to select the GLTF format and start the download! |
|
| 47 | 55 | ||
| 48 | - | >>SCREENSHOT |
|
| 56 | + | <Image |
|
| 57 | + | src="https://miro.medium.com/v2/resize:fit:4800/format:webp/1*0z9cGRbGbAWoflqk7rU0yw.png" |
|
| 58 | + | alt="screenshot of aerial export screen" |
|
| 59 | + | width={1920} |
|
| 60 | + | aspectRatio={16/9} |
|
| 61 | + | /> |
|
| 49 | 62 | ||
| 50 | 63 | Ok so we got our 3D file for our environment, now lets do some 3D objects as well! The process is pretty similar, except for 3D objects we’ll switch to the “photo” mode instead of the LiDAR mode. The photo mode will take a bunch of different pictures and put them together to make a 3D model! In the video below you can see what the process looks like as I scan one of my prized possessions, a 1930's edition of Moby Dick illustrated by Rockwell Kent. |
|
| 51 | 64 | ||
| 52 | - | >>INSERT VIMEO |
|
| 65 | + | <div style="padding:216.22% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/704181596?h=92cada3864" style="position:absolute;top:0;left:0;width:100%;height:100%;" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe></div><script src="https://player.vimeo.com/api/player.js"></script> |
|
| 53 | 66 | ||
| 54 | 67 | Once we finish scanning the book, I like to select the higher end of the quality allowance, and I like to use the object masking to get all the fine details. These photo mode objects are a bit more work, so when you take one Polycam sends it off to a server for higher powered processing. Due to how intense the work is, you can only take 150 of these a month, but I don’t think that will be an issue for most people. Once they finish processing it, the model looks like this! |
|
| 55 | 68 | ||
| 56 | - | >>INSERT VIMEO |
|
| 69 | + | <div style="padding:216.22% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/704185926?h=2a929c3d73" style="position:absolute;top:0;left:0;width:100%;height:100%;" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe></div><script src="https://player.vimeo.com/api/player.js"></script> |
|
| 57 | 70 | ||
| 58 | 71 | The download process looks exactly the same as we did the desk, very easy! Also while you’re still in Polycam, you can edit, adjust, crop, etc. your model all inside their app or website, so that way when the model is exported it’s ready to be turned into an NFT! |
|
| 59 | 72 | ||
| 71 | 84 | ||
| 72 | 85 | Let’s log into Pinata and upload our file. Really simple, just click on the upload button in the top left, give it a name, and upload! |
|
| 73 | 86 | ||
| 74 | - | >>SCREENSHOT |
|
| 87 | + | <Image |
|
| 88 | + | src="https://miro.medium.com/v2/resize:fit:4800/format:webp/1*v-x8ltZQ0ep6vlmqoPn2WA.png" |
|
| 89 | + | alt="uploading screen at pinata" |
|
| 90 | + | width={1920} |
|
| 91 | + | aspectRatio={16/9} |
|
| 92 | + | /> |
|
| 75 | 93 | ||
| 76 | 94 | Then we just need to choose a subdomain and make sure its available. If it is, click next! |
|
| 77 | 95 | ||
| 206 | 224 | ||
| 207 | 225 | Then using a wallet like Phantom, click on “Add / Connect wallet, select “import private key,” then paste in our keypair from earlier. Once it’s in your wallet you will want to click on the settings icon in the bottom right, scroll down to “change network” and set it to “Devnet.” Once you do that, go back to your NFTs page and you should see it!! |
|
| 208 | 226 | ||
| 209 | - | >>SCREENSHOT |
|
| 227 | + |  |
|
| 210 | 228 | ||
| 211 | 229 | ## Conclusion |
|
| 212 | 230 | ||
| 5 | 5 | tags: ["web3", "nfts", "tutorials"] |
|
| 6 | 6 | ogImage: "https://miro.medium.com/v2/resize:fit:4800/format:webp/1*KxoVDEZFH3mJrlfeguMYjg.jpeg" |
|
| 7 | 7 | --- |
|
| 8 | + | import { Image } from "@astrojs/image/components"; |
|
| 9 | + | ||
| 8 | 10 | ||
| 9 | 11 | As a believer in NFTs and Web3, I am always ecstatic to see what can be done with this new technology. I get bullish over new projects, experimental ideas, and cutting edge utility (especially when it’s something we make at Pinata like [Submarine.me](https://submarine.me)). However, I don’t look at this Metaverse with rose colored glasses. There are many imperfections in this space, and one of the worst ones is environmental impact. |
|
| 10 | 12 | ||
| 11 | 13 | While I love dooting around on my computer, I also love the outdoors. I love hiking, seeing mountains, hearing rivers, and smelling wildflowers. I love hearing birds in the morning and geese at night. I love to watch my son experience nature and get excited over a butterfly. So yeah, it kinda kills me to think of how this wonderful industry of crypto can harm this amazing planet. |
|
| 12 | 14 | ||
| 13 | - |  |
|
| 15 | + | <Image |
|
| 16 | + | src="https://cdn-images-1.medium.com/max/2400/1*xQEP67xsPsQ4vU7wjKLFBw.png" |
|
| 17 | + | alt="ethereum carbon emissions chart" |
|
| 18 | + | width={1920} |
|
| 19 | + | aspectRatio={16/9} |
|
| 20 | + | /> |
|
| 14 | 21 | ||
| 15 | 22 | The energy consumed by proof of work blockchains is staggering. It’s no secret, and if we want to enjoy this planet we need to accept it. I know I feel defensive when someone attacks something I enjoy, but it helps to take a deep breath and ask the big questions: “could I be wrong?” If crypto is putting the planet in danger, what do we do? |
|
| 16 | 23 | ||
| 19 | 26 | This is where [Aerial](https://aerial.is/) steps in. Aerial is a sustainability platform that helps users track their carbon footprint and make donations to help offset their carbon footprint. They are known for their beautiful [mobile application](https://aerial.is/download), but more recently they have developed an API that can track and estimate the carbon footprint of NFT projects and crypto! Per their website, “Emissions are calculated based on the energy consumption of the [Ethereum network](http://ethereumenergyconsumption.com/) and the average [gas used](https://etherscan.io/chart/gasused) per transaction.” Since [Pinata](https://pinata.cloud/) is the home of NFT media we want to always support initiatives like this to make NFTs more sustainable! |
|
| 20 | 27 | ||
| 21 | 28 | They have some awesome and simple ways you can integrate their widget to your website that looks something like this: |
|
| 29 | + | ||
| 22 | 30 | ```javascript |
|
| 23 | 31 | <iframe src="https://www.aerial.is/nft/embed?address=0x3e88721fa41d5e102d54b4a04e550222efdd234d"> |
|
| 24 | 32 | ``` |
|
| 25 | - |  |
|
| 33 | + | ||
| 34 | + | <Image |
|
| 35 | + | src="https://cdn-images-1.medium.com/max/2000/1*IPAefM4T_NiRygdri_DzhA.png" |
|
| 36 | + | alt="screenshot of widget" |
|
| 37 | + | width={1920} |
|
| 38 | + | aspectRatio={6/2} |
|
| 39 | + | /> |
|
| 40 | + | ||
| 26 | 41 | ||
| 27 | 42 | In this post we’ll take their API a step further and build our own custom widget. We can use it in our frontend website that displays more details about the project’s emissions with the goal of making visitors more aware! |
|
| 28 | 43 | ||
| 29 | 44 | If you want to follow along for this tutorial, you’ll need to have npm installed and be familiar with a frontend framework like React. First thing we’ll do is create a new React app and CD into it. |
|
| 45 | + | ||
| 30 | 46 | ```bash |
|
| 31 | 47 | npx create-react-app aerial-component |
|
| 32 | 48 | ||
| 33 | 49 | cd aerial-component && npm start |
|
| 34 | 50 | ``` |
|
| 51 | + | ||
| 35 | 52 | Then we’ll delete the CSS files and boilerplate so we are left with this in App.js |
|
| 53 | + | ||
| 36 | 54 | ```javascript |
|
| 37 | 55 | function App() { |
|
| 38 | 56 | return ( |
|
| 43 | 61 | ||
| 44 | 62 | export default App; |
|
| 45 | 63 | ``` |
|
| 64 | + | ||
| 46 | 65 | Now let’s make a new component. Create a new file in the src folder called Aerial.js and fill it with this starter code |
|
| 66 | + | ||
| 47 | 67 | ```javascript |
|
| 48 | 68 | const Aerial = () => { |
|
| 49 | 69 | return ( |
|
| 52 | 72 | } |
|
| 53 | 73 | ||
| 54 | 74 | export default Aerial; |
|
| 75 | + | ||
| 55 | 76 | ``` |
|
| 77 | + | ||
| 56 | 78 | Now let’s import the new component to our App.js |
|
| 79 | + | ||
| 57 | 80 | ||
| 58 | 81 | ```javascript |
|
| 59 | 82 | import Aerial from "./Aerial" |
|
| 68 | 91 | ||
| 69 | 92 | export default App; |
|
| 70 | 93 | ``` |
|
| 94 | + | ||
| 71 | 95 | If you run npm start you should see your basic app with “Aerial” in the top left! |
|
| 72 | 96 | ||
| 73 | 97 | Now that we have our new component ready to go, we need to start making some API calls and fetching the data. If you need a reference for how to use Aerial’s API you can see their reference [here](https://www.notion.so/aerial/Aerial-API-343ebee875784ca18c244a5aae9fa7d3). |
|
| 74 | 98 | ||
| 75 | 99 | It’s really quite easy, all we have to do to fetch some basic data is use the following format |
|
| 100 | + | ||
| 76 | 101 | ``` |
|
| 77 | 102 | GET https://aerial.is/_nft/<address> |
|
| 78 | 103 | ``` |
|
| 104 | + | ||
| 79 | 105 | This will return data in the following format |
|
| 106 | + | ||
| 80 | 107 | ```json |
|
| 81 | 108 | { |
|
| 82 | 109 | "co2": <emissions in CO2>, |
|
| 88 | 115 | "transactions_offset": <number of transactions already offset> |
|
| 89 | 116 | } |
|
| 90 | 117 | ``` |
|
| 118 | + | ||
| 91 | 119 | So let’s give it a shot! First thing we need to do is install Axios to help us with our API calls. Go back to the terminal and run |
|
| 120 | + | ||
| 92 | 121 | ```bash |
|
| 93 | 122 | npm install axios |
|
| 94 | 123 | ``` |
|
| 124 | + | ||
| 95 | 125 | Now make sure to import it into the top of our Aerial component like so |
|
| 126 | + | ||
| 96 | 127 | ```javascript |
|
| 97 | 128 | import axios from "axios" |
|
| 98 | 129 | ``` |
|
| 130 | + | ||
| 99 | 131 | Now we’re going to make a quick function that will get the data. For our example we’re going to use the NFT contract address 0x2acab3dea77832c09420663b0e1cb386031ba17b. |
|
| 132 | + | ||
| 100 | 133 | ```javascript |
|
| 101 | 134 | const getEmissionsData = async () => { |
|
| 102 | 135 | try{ |
|
| 107 | 140 | } |
|
| 108 | 141 | } |
|
| 109 | 142 | ``` |
|
| 143 | + | ||
| 110 | 144 | To run this function we’ll use the useEffect hook to fetch the data as we load the app. To do that we simply need to import it at the top like so |
|
| 145 | + | ||
| 111 | 146 | ```javascript |
|
| 112 | 147 | import { useEffect } from "react"; |
|
| 113 | 148 | ``` |
|
| 149 | + | ||
| 114 | 150 | Then we need to run the function inside useEffect, |
|
| 151 | + | ||
| 115 | 152 | ```javascript |
|
| 116 | 153 | useEffect(()=> { |
|
| 117 | 154 | getEmissionsData() |
|
| 118 | 155 | }, []) |
|
| 119 | 156 | ``` |
|
| 157 | + | ||
| 120 | 158 | This is what our code will look like with everything in place: |
|
| 159 | + | ||
| 121 | 160 | ```javascript |
|
| 122 | 161 | ||
| 123 | 162 | import { useEffect } from "react"; |
|
| 150 | 189 | ||
| 151 | 190 | If we run the app and check the dev console, we can see our data! |
|
| 152 | 191 | ||
| 153 | - |  |
|
| 192 | + | <Image |
|
| 193 | + | src="https://cdn-images-1.medium.com/max/2000/1*UrdopTgDhErJObLI3V8DwQ.png" |
|
| 194 | + | alt="dev tools" |
|
| 195 | + | width={1920} |
|
| 196 | + | aspectRatio={16/4} |
|
| 197 | + | /> |
|
| 154 | 198 | ||
| 155 | 199 | Now that we have the data, it’s as simple as displaying it so users on our website can see it! |
|
| 156 | 200 | ||
| 157 | 201 | To store the data we’ll import the useState hook at the top of our app along with useEffect |
|
| 202 | + | ||
| 158 | 203 | ```javascript |
|
| 159 | 204 | import { useEffect, useState } from "react" |
|
| 160 | 205 | ``` |
|
| 161 | 206 | ||
| 162 | 207 | Then right above our function to grab the data, we’ll declare our state variable as an empty array where we can push stuff in later. |
|
| 208 | + | ||
| 163 | 209 | ```javascript |
|
| 164 | 210 | const [emissionsData, setEmissionsData] = useState([]) |
|
| 165 | 211 | ``` |
|
| 212 | + | ||
| 166 | 213 | Now all we have to do is edit our function just a little bit to push that data into our state using the “setEmissionsData”! Here is our function now |
|
| 214 | + | ||
| 167 | 215 | ```javascript |
|
| 168 | 216 | const getEmissionsData = async () => { |
|
| 169 | 217 | try{ |
|
| 175 | 223 | } |
|
| 176 | 224 | } |
|
| 177 | 225 | ``` |
|
| 226 | + | ||
| 178 | 227 | The next thing we’re gonna do is create two components inside our file, one as a loading indicator, and the other as the data we want to display. To do this we’ll just make two more functions like this |
|
| 228 | + | ||
| 179 | 229 | ```javascript |
|
| 180 | 230 | const loading = () => ( |
|
| 181 | 231 | <div className="loading-container"> |
|
| 192 | 242 | ) |
|
| 193 | 243 | } |
|
| 194 | 244 | ``` |
|
| 245 | + | ||
| 195 | 246 | To switch between the two we’ll create a new state called “isLoading” right underneath our previous state. We’ll set the default value to “false” for now |
|
| 247 | + | ||
| 196 | 248 | ```javascript |
|
| 197 | 249 | const [emissionsData, setEmissionsData] = useState([]) |
|
| 198 | 250 | const [isLoading, setIsLoading] = useState(false) |
|
| 199 | 251 | ``` |
|
| 252 | + | ||
| 200 | 253 | Back in our getEmissionsData function we need to turn the “loading” on when we start the request, and then off when we’re done. |
|
| 254 | + | ||
| 201 | 255 | ```javascript |
|
| 202 | 256 | const getEmissionsData = async () => { |
|
| 203 | 257 | try{ |
|
| 211 | 265 | } |
|
| 212 | 266 | } |
|
| 213 | 267 | ``` |
|
| 268 | + | ||
| 214 | 269 | Finally, way down at the bottom where we render the whole app, we’ll add in some conditional rendering to say “display the loading component while loading, then display the data component when not loading.” |
|
| 270 | + | ||
| 215 | 271 | ```javascript |
|
| 216 | 272 | return ( |
|
| 217 | 273 | <div className="aerial-container"> |
|
| 219 | 275 | </div> |
|
| 220 | 276 | ) |
|
| 221 | 277 | ``` |
|
| 278 | + | ||
| 222 | 279 | As a quick recap this is what our component looks like at the moment |
|
| 280 | + | ||
| 223 | 281 | ```javascript |
|
| 224 | 282 | import { useState, useEffect } from "react" |
|
| 225 | 283 | import axios from "axios" |
|
| 274 | 332 | Ok now the good part! Time to parse that data and display it. We’re going to go over a few of the pieces of data and how you may want to display them. |
|
| 275 | 333 | ||
| 276 | 334 | The first is the CO2 emissions, which the API returns as a raw number in the unit of Kg. The best way to make this number manageable in my opinion is to round up the number, and use some javascript to add the commas for each three digits. So back in our emissionsComponent, I have declared the following variable from our saved state. |
|
| 335 | + | ||
| 277 | 336 | ```javascript |
|
| 278 | 337 | const co2 = new Intl.NumberFormat().format(Math.round(emissionsData.co2)) |
|
| 279 | 338 | ``` |
|
| 339 | + | ||
| 280 | 340 | Next up is the gas used for this project, and for this one it returns a whole number so no need to round it up. We’ll just format it to be readable. |
|
| 341 | + | ||
| 281 | 342 | ```javascript |
|
| 282 | 343 | const gas = new Intl.NumberFormat().format(emissionsData.gas) |
|
| 283 | 344 | ``` |
|
| 345 | + | ||
| 284 | 346 | Aerial of course also provides their unit for donations to offset the carbon emissions they call “credits.” The API can return the total credits need to make the NFT project carbon neutral, how many are purchased so far, and how much it would cost in total to offset the project in USD. To make this data more readable, we want to display how many credits have been purchased, how many are needed to offset, and how much it would cost to completely offset the project. We just need a little math to make that happen! |
|
| 285 | 347 | ||
| 286 | 348 | For the credits remaining, we just need to subtract the credits already purchased from the total credits needed to offset like so. |
|
| 349 | + | ||
| 287 | 350 | ```javascript |
|
| 288 | 351 | const creditsRemaining = new Intl.NumberFormat().format(emissionsData.credits - emissionsData.credits_purchased) |
|
| 289 | 352 | ``` |
|
| 353 | + | ||
| 290 | 354 | Of course we want to display how many have already purchased and that’s pretty simple. |
|
| 355 | + | ||
| 291 | 356 | ```javascript |
|
| 292 | 357 | const creditsPurchased = new Intl.NumberFormat().format(emissionsData.credits_purchased) |
|
| 293 | 358 | ``` |
|
| 359 | + | ||
| 294 | 360 | Now the more complicated part is calculating how much the remaining cost is. The API gives us the total cost, but it does not include how much has been spent. So for us to get this number we need to divide the emissions cost with the total credits needed to offset, then multiply that against the total emissions credits minus the credits already purchased. In the end it looks like this! |
|
| 361 | + | ||
| 295 | 362 | ```javascript |
|
| 296 | 363 | const cost = new Intl.NumberFormat().format((emissionsData.cost / emissionsData.credits) * (emissionsData.credits - emissionsData.credits_purchased)) |
|
| 297 | 364 | ``` |
|
| 365 | + | ||
| 298 | 366 | Lastly, we want the number of total number of transactions already offset. |
|
| 367 | + | ||
| 299 | 368 | ``` |
|
| 300 | 369 | const transactions = new Intl.NumberFormat().format(emissionsData.transactions) |
|
| 301 | 370 | ``` |
|
| 371 | + | ||
| 302 | 372 | Alright that was a bit of work to get sorted, but now we can easily plug this into our emissionsComponent so people can see the data in a more easy to read format. We’re also going to display this in a nice grid with each data cell in a box, so our code inside emissions is going to look like this. |
|
| 373 | + | ||
| 303 | 374 | ```javascript |
|
| 304 | 375 | return ( |
|
| 305 | 376 | <div className="data-container"> |
|
| 336 | 407 | </div> |
|
| 337 | 408 | ) |
|
| 338 | 409 | ``` |
|
| 410 | + | ||
| 339 | 411 | At the bottom we’ve also added a button where a user can click on it and be directed to Aerials page for that particular NFT project, where they can make purchase credits to help offset that project. |
|
| 340 | 412 | ||
| 341 | 413 | To make this whole component feel clean as well as themed for the project, we took some colors and styled from DeadFellaz and added it to this page with some CSS; we also added a fun Lottie animation for the loading component instead of just a header that says loading. In the end our code looks like this! |
|
| 1 | - | --- |
|
| 2 | - | title: "Test" |
|
| 3 | - | publishDate: "18 May 2022" |
|
| 4 | - | description: "Learn how to scan and mint real life objects on Solana" |
|
| 5 | - | tags: ["web3", "nfts", "tutorials"] |
|
| 6 | - | --- |
|
| 7 | - | ||
| 8 | - | The growth and evolution of NFTs has come a long way from the early days. Some of the early NFT projects were simple .png files or a link to a YouTube video, but now they are an entire industry that consumes brand, utility, even augmented reality. Metaverses, 3D objects, and other virtual reality experiences are all the rage, and I firmly believe we will see more of this in the near future. |
|
| 9 | - | ||
| 10 | - | One unique tool that I stumbled upon was Polycam. Polycam is a mobile iOS app that utilizes the iPhone’s LiDAR scanner to map 3D objects and environments. 3D NFTs are certainly popular, but what about 3D NFTs of real life objects? Or even better: real life environments? I think this is an angle that not many people have thought about creating, and opens up a whole new realm of artistic expression in ways people have not seen before. |
|
| 11 | - | ||
| 12 | - | In this tutorial we’ll cover how to use Polycam to scan and create a 3D models and environments, and then we’ll cover how to make them into NFTs using Pinata and Solana. |
|
| 13 | - | ||
| 14 | - | ## Scanning with Polycam |
|
| 15 | - | ||
| 16 | - | To get started you’ll want to download the Polycam app on the App Store. Be aware that this is only for iPhones, and scanning environments will be more effective if you have a LiDAR scanner on your iPhone. Having a LiDAR scanner is not necessary though! Once you download it you will need to make an account with them and start their 14 day free trial. |
|
| 17 | - | ||
| 18 | - | Once you do that Polycam will take you to the “captures” page where you can see all your scans. To learn how the scan process works, I would highly recommend their well done tutorials on their website and in the app. |
|
| 19 | - | ||
| 20 | - | [Using LiDAR Mode to Capture Large Spaces](https://learn.poly.cam/capturing-large-spaces) |
|
| 21 | - | ||
| 22 | - | [Using Photo Mode to Capture 3D Objects](https://learn.poly.cam/building-a-studio-for-photo-mode-captures) |
|
| 23 | - | ||
| 24 | - | In short, you will want to use the LiDAR mode when you are trying to scan environments or large spaces, and for 3D objects you will want to use the photo mode! |
|
| 25 | - | ||
| 26 | - | For this tutorial I’m going to scan my desk space using the LiDAR method, and for the 3D objects we’ll use an old book, and of course Pinnie! |
|
| 27 | - | ||
| 28 | - | With the video below you can get glimpse of how the LiDAR scanner maps over surfaces. Taking it real slow and covering every angle really helps with scanning environments. |
|
| 29 | - | ||
| 30 | - | >>INSERT VIMEO |
|
| 31 | - | ||
| 32 | - | After you’re done scanning there will be a processing step that will take all the data and map it into a 3D environment! |
|
| 33 | - | ||
| 34 | - | >>INSERT VIMEO |
|
| 35 | - | ||
| 36 | - | Once it’s processed you can go ahead and view the 3D model/environment! Polycam really is first class; you can create videos, you can view the model in Augmented Reality, it just has so many awesome features! My model isn’t the cleanest since I have so many small detailed objects on my desk, but for something a bit simpler this feature is amazing. |
|
| 37 | - | ||
| 38 | - | >>INSERT VIMEO |
|
| 39 | - | ||
| 40 | - | Now that we got our model, we can upload it to the cloud and look at it through our web browser! Just click on the little cloud icon on the top of the screen when viewing your model and it will be uploaded to your cloud storage with Polycam. |
|
| 41 | - | ||
| 42 | - | Once viewing it in the web browser, we can download the model by clicking “export.” |
|
| 43 | - | ||
| 44 | - | >>SCREENSHOT |
|
| 45 | - | ||
| 46 | - | From there we want to select the GLTF format and start the download! |
|
| 47 | - | ||
| 48 | - | >>SCREENSHOT |
|
| 49 | - | ||
| 50 | - | Ok so we got our 3D file for our environment, now lets do some 3D objects as well! The process is pretty similar, except for 3D objects we’ll switch to the “photo” mode instead of the LiDAR mode. The photo mode will take a bunch of different pictures and put them together to make a 3D model! In the video below you can see what the process looks like as I scan one of my prized possessions, a 1930's edition of Moby Dick illustrated by Rockwell Kent. |
|
| 51 | - | ||
| 52 | - | >>INSERT VIMEO |
|
| 53 | - | ||
| 54 | - | Once we finish scanning the book, I like to select the higher end of the quality allowance, and I like to use the object masking to get all the fine details. These photo mode objects are a bit more work, so when you take one Polycam sends it off to a server for higher powered processing. Due to how intense the work is, you can only take 150 of these a month, but I don’t think that will be an issue for most people. Once they finish processing it, the model looks like this! |
|
| 55 | - | ||
| 56 | - | >>INSERT VIMEO |
|
| 57 | - | ||
| 58 | - | The download process looks exactly the same as we did the desk, very easy! Also while you’re still in Polycam, you can edit, adjust, crop, etc. your model all inside their app or website, so that way when the model is exported it’s ready to be turned into an NFT! |
|
| 59 | - | ||
| 60 | - | Last but not least, we got a model of Pinnie too 😉 |
|
| 61 | - | ||
| 62 | - | [Pinata Polycam Capture](https://poly.cam/capture/FAE73483-C416-49D6-B92C-33260BF924E1) |
|
| 63 | - | ||
| 64 | - | ## Creating 1/1 NFTs on Solana |
|
| 65 | - | ||
| 66 | - | Alright alright alright, we got our models from Polycam, now lets turn them into 1/1 NFTs on Solana! |
|
| 67 | - | ||
| 68 | - | First thing you’ll want to do is get a [Pinata account](https://pinat.cloud). I would recommend getting the professional account so you can use a Dedicated Gateway, you’ll see why as we go further! |
|
| 69 | - | ||
| 70 | - | There’s a lot of great benefits of using IPFS for NFTs, such as [content addressability](https://docs.ipfs.io/concepts/content-addressing/) and [portability](https://medium.com/pinata/web3-data-portability-through-ipfs-saved-hicetnunc-724e3df2948d), but especially speed using a dedicated gateway. Since Solana is still adopting IPFS, not all the wallets and marketplaces have their own gateway solutions to resolve links like “ipfs://CID.” However with our own dedicated gateway we can use a standard “https://” link and deliver it with speed. You’ll see how we’ll do this in a bit! |
|
| 71 | - | ||
| 72 | - | Let’s log into Pinata and upload our file. Really simple, just click on the upload button in the top left, give it a name, and upload! |
|
| 73 | - | ||
| 74 | - | >>SCREENSHOT |
|
| 75 | - | ||
| 76 | - | Then we just need to choose a subdomain and make sure its available. If it is, click next! |
|
| 77 | - | ||
| 78 | - | If we just clicked on this file to preview it, it’s gonna take us straight to download since the browser doesn’t know what to do. That’s ok! We’re gonna format the link for our NFT metadata. It will look something like this. |
|
| 79 | - | ||
| 80 | - | ``` |
|
| 81 | - | https://{your-subdomain}.mypinata.cloud/ipfs/{your-3d-file-cid}?filename={file-name-and-extension} |
|
| 82 | - | ``` |
|
| 83 | - | ||
| 84 | - | For our particular CID the link will look like this! |
|
| 85 | - | ||
| 86 | - | ``` |
|
| 87 | - | ``` |
|
| 88 | - | ||
| 89 | - | Ok our 3D file is on IPFS, the next step is to create a metadata file that will point to that 3D file. Open up your terminal and run: |
|
| 90 | - | ||
| 91 | - | ```bash |
|
| 92 | - | mkdir 3d-nfts && cd 3d-nfts && touch pinnie.json |
|
| 93 | - | ``` |
|
| 94 | - | ||
| 95 | - | Then open up that pinnie.json file in your text editor of choice. Since we’re using Solana we will want to use [Metaplex Token Metadata Standard](https://docs.metaplex.com/token-metadata/Versions/v1.0.0/nft-standard#json-structure) which you will definitely want to save as a reference, but we’ll be simplifying ours just a little bit. |
|
| 96 | - | ||
| 97 | - | ||
| 98 | - | Couple of things you’ll want to take note here. We could use an image URL if you wanted a backup, just make sure you upload a separate file to Pinata. For our example I’ve left it as null. The key thing to notice is the “animation_url” which I have set to our link we created earlier. Under properties and files, we left the image null again, and created another one that includes: |
|
| 99 | - | ||
| 100 | - | ```json |
|
| 101 | - | ``` |
|
| 102 | - | ||
| 103 | - | The uri is the link to our content, and the type defines the kind of file we want to use, which in this case is virtual reality (vr) and the file format (glb). Once you get familiar with the metadata standard it’s pretty straight forward. Now that we created this metadata file, save it and upload it to Pinata as well. Once it’s uploaded take note of the CID and save the link to it, should look something like this: |
|
| 104 | - | ||
| 105 | - | ``` |
|
| 106 | - | ``` |
|
| 107 | - | ||
| 108 | - | We’re really close to minting this NFT! [Solana](https://solana.com/) is an up and coming blockchain that is capable of incredible speeds and low transactions fees. Before we go any further you’ll want to make sure you have a couple of things installed on your computer: |
|
| 109 | - | ||
| 110 | - | - [Solana CLI](https://docs.solana.com/cli/install-solana-cli-tools) |
|
| 111 | - | - [Metaboss](https://github.com/samuelvanderwaal/metaboss) |
|
| 112 | - | ||
| 113 | - | Be sure to follow the instructions for installing each very carefully! The Solana CLI is the tool that will let us interact with the Solana blockchain, and Metaboss is nicknamed “The Solana Metaplex NFT ‘Swiss Army Knife’” and rightly so. It is packed with features, including the minting NFTs! |
|
| 114 | - | ||
| 115 | - | Once you’ve installed both, let’s make sure the Solana CLI is setup properly by running the following command. |
|
| 116 | - | ||
| 117 | - | ```bash |
|
| 118 | - | solana --version |
|
| 119 | - | ``` |
|
| 120 | - | ||
| 121 | - | If that returns the version then we are good to go! Next thing we’ll do is create a wallet, set our network to devnet, and get some fake sol. To create a new wallet run the command below. |
|
| 122 | - | ||
| 123 | - | ```bash |
|
| 124 | - | solana-keygen new --outfile ~/.config/solana/devnet.json |
|
| 125 | - | ``` |
|
| 126 | - | ||
| 127 | - | This will create a file on your computer and is the code version of a new Solana wallet! Next we want to set our Solana config to use this wallet by default. |
|
| 128 | - | ||
| 129 | - | ```bash |
|
| 130 | - | solana config set --keypair ~/.config/solana/devnet.json |
|
| 131 | - | ``` |
|
| 132 | - | ||
| 133 | - | Last but not least, we’ll set our Solana config to use the devnet environment so we can use fake money and have room to mess around. |
|
| 134 | - | ||
| 135 | - | ```bash |
|
| 136 | - | solana config set --url https://api.devnet.solana.com |
|
| 137 | - | ``` |
|
| 138 | - | ||
| 139 | - | Now we can make sure all is good by running: |
|
| 140 | - | ||
| 141 | - | ```bash |
|
| 142 | - | solana config get |
|
| 143 | - | ``` |
|
| 144 | - | ||
| 145 | - | This will return what wallet we’re using and what network we’re on! Last step is to get some test SOL, which is so easy! Just run the command below. Once it’s done it should return a balance! |
|
| 146 | - | ||
| 147 | - | ```bash |
|
| 148 | - | solana airdrop 2 |
|
| 149 | - | ``` |
|
| 150 | - | ||
| 151 | - | As far as Metaboss goes, it’s pretty simple to install after installing Solana. Once you have installed it, run the following command to make sure it’s ready to go. |
|
| 152 | - | ||
| 153 | - | ```bash |
|
| 154 | - | metaboss --version |
|
| 155 | - | ``` |
|
| 156 | - | ||
| 157 | - | To mint our NFT, Metaboss makes it so easy! We just gotta run this command: |
|
| 158 | - | ||
| 159 | - | ```bash |
|
| 160 | - | ``` |
|
| 161 | - | ||
| 162 | - | Let’s break down what’s happening here. Metaboss is going to mint one token for us, and we set the “external-metadata-uri” to the url we created a little while ago that points to our uploaded metadata. Then we just set the keypair or wallet to authorize the transaction, and that’s it! If it worked you should get a result with the transaction ID and the mint account! |
|
| 163 | - | ||
| 164 | - | Ok but we want to see it right? All we gotta do is open our ~/.config/solana/devnet.json file, and copy the numbers in it (this is your private key, keep it safe and do not share it!) |
|
| 165 | - | ||
| 166 | - | Then using a wallet like Phantom, click on “Add / Connect wallet, select “import private key,” then paste in our keypair from earlier. Once it’s in your wallet you will want to click on the settings icon in the bottom right, scroll down to “change network” and set it to “Devnet.” Once you do that, go back to your NFTs page and you should see it!! |
|
| 167 | - | ||
| 168 | - | >>SCREENSHOT |
|
| 169 | - | ||
| 170 | - | ## Conclusion |
|
| 171 | - | ||
| 172 | - | Polycam really introduces a whole new way of how content can be created using modern tech. You can imagine how this might be used for journalism, where instead of just looking at a photo of a story, you can view it as a 3D object with augmented reality. Someone who explores caves can share their experience as a 3D environment! Paired with Solana as a much faster and affordable layer one solution, and [Pinata](https://pinata.cloud) to deliver IPFS content quickly, the possibilities are endless! |
|
| 173 | - | --- |
| 62 | 62 | <article class="flex-grow break-words"> |
|
| 63 | 63 | <div id="blog-hero"><BlogHero content={post} /></div> |
|
| 64 | 64 | <div |
|
| 65 | - | class="prose prose-sm prose-cactus mt-12 prose-headings:font-semibold prose-headings:before:absolute prose-headings:before:-ml-4 prose-headings:before:text-accent prose-headings:before:content-['#'] prose-th:before:content-none" |
|
| 65 | + | class="prose prose-sm prose-cactus mt-12 prose-headings:font-semibold prose-headings:before:absolute prose-headings:before:-ml-4 prose-headings:before:text-accent prose-headings:before:content-['#'] prose-th:before:content-none max-w-xs sm:max-w-prose prose-code:break-normal prose-code:overflow-x-scroll sm:prose-code:break-words" |
|
| 66 | 66 | > |
|
| 67 | 67 | <slot /> |
|
| 68 | 68 | </div> |