字幕表 動画を再生する 英語字幕をプリント [BELL RINGING] Hello, and welcome back to part 2 of building your own Processing library in Java. Look, I'm working with Eclipse! I love eclipse! All of you will complain that I'm using Eclipse, and I don't care. I love Eclipse. It's one of the first places I learned to program, so it has a special place in my heart. So what I did in the previous part-- you're probably going to want to go back to watch it if you're here and you didn't-- was set up the development environment, so install Eclipse, make sure I have Processing installed, setup all the paths, the build paths, the project, the template, the cloning, all of that stuff. So what I am here right now, I successfully built the library. So it shows up now in Processing under Import Library. And, remember, I'm choosing OpenSimplexNoise as the topic. It's very arbitrary, but I want to build something that's actually useful and can be published as a real library. But the library is here, but if I click this, it automatically adds the import statement, which you can see is just template.library.*. So in this video, what I want to do is code the library itself and make one example that uses it. Probably the hardest part of making a library is being thoughtful about the design of the library API itself, how you make the examples, as well as documenting it. So that's more of a broader topic related to how to maintain and publish an open-source library, but I'm going to mostly focus on the technical details of building the thing. And maybe towards the end, I can circle back and talk more about those key important concepts and topics to having a healthy open-source project. So first thing that I want to do, if I want to customize this, it I should say something like "import shiffman.opensimplexnoise," or something like that. I mean, I don't think that's what I'm going to call it. I'm going to go back to Eclipse. I'm going to go over here, and I'm looking for under Source. And so, look, this is what's known as a package, template.library. And so, because the package name in the template is just "template.library," that's what the import was, template.library. So I'm going to right-click on this, I'm going to go to Refactor, and click Rename. And then I'm going to come here, and I got to pick a name for it. Let's call it "algorithms.noise." Ultimately, I think what could be exciting about this library is to implement a bunch of different noise algorithms, OpenSimplex noise, fractal noise, gradient noise, Worley noise. So many different kinds of noise algorithms could be in here that would be additions and enhancements to the built-in, original Perlin noise algorithm that's in Processing itself. So that'll be my name. I'm going to click OK, excellent. Now I want to go into the source code, which is called "HelloLibrary." So I am going to rename this also by going to Refactor, Rename. And I'm going to name that-- let's call this particular Java class "OpenSimplexNoise." And I'm going to do Finish. OK, great. I'm going to go over here, and there we go. Let's try rebuilding the library. We don't need to rebuild it at every single stage, but let's just rebuild it to see if what I did at least shows up with the proper naming conventions. So I go to Window, Show View, Ant. Click here, and do Ant Build. BUILD SUCCESSFUL is what you're looking for. Go back to Processing, Sketch, Import Library, OpenSimplexNoise. There we go! Interestingly, it's giving me an error message. Let's try restarting Processing and see what happens. All right, I restarted Processing, and the error message went away. So certain things that you change, if you're changing the package name, even though the new library files are being built and brought over into Processing, Processing has loaded what it thought all the package names were when it started up, so you have to restart. So I don't think with every single change you make while you're building the library you're going to have to restart Processing, but that certainly is something you'll have to do from time to time. One of the things I like to do when designing an open-source library is actually write the example first in the way that I imagine that it might be. So even though I haven't built any of the functionality of the library itself, what I want to do is I want to take a simple processing Perlin noise example that uses just the built-in original Perlin noise from the 1980s algorithm, and then change that example to use OpenSimplex noise. So if I go to Examples, under Basics, under Math, let's just take Noise1D, and let's look at this example. This Noise1D example is mapping the x location of this circle it's drawing to the noise implementation in Processing. So I'm going to grab all this code, copy it, close this out, and paste it in here. And I'm going to imagine what I might do. So I might do something like, OpenSimplexNoise noise. And then I'm going to say "noise is a new OpenSimplexNoise." So presumably the idea is that OpenSimplexNoise would be an object inside of the package algorithms.noise. Maybe I want to name that just "OpenSimplex," because by definition it's noise. Who knows, but I want to create a new instance of it. Maybe, optionally, there could be a seed that goes in here, because I could be randomly seeding the noise. And then, what I would do is, say-- (CHUCKLING) and so let me call it something different for it to be less confusion. Let me call it "osnoise" for OpenSimplexNoise. And then, probably what I would want to do is say "osnoise.value," pass it this X offset. And, actually, that's it! Because, really, this is such a like-- even though the OpenSimplexNoise algorithm is quite complex, I just want one function that gives me the noise value back. And I'll call that value-- or, I could have called it "noise." I don't know what to call it. But, again, these types of naming an API design decisions, while incredibly important, I'm going to maybe tackle later, and through user testing and discussion, and are less crucial right now in terms of the nuts and bolts of how to build your library. How to think about making an open-source library, it's so important! But right now I can just pick something. Let's pick value. Let me go back to the library code. And I'm going to add a function now. I'm going to add a function called "public value." And it's going to receive an argument, like X offset, xoff. And I'm going to say "return negative 5." So I just want to test out this idea. I want to add a function called-- oh! This should be "public float value." Because it's a Java function that returns a float. It receives a float. So, again, this is not the OpenSimplexNoise (CHUCKLING) algorithm, but I am just going to have it return negative 5 to see if it works. And let's actually just give it the number 50. Well, actually, noise should return a value between 0 and 1 or, in this case, maybe between negative 1 and 1. So let's actually make it negative 0.5. And, in Java, if I want it to be a float, I've actually got to add that f to indicate float. So, once again, I am going to build the library. The library is rebuilt. Let's go back to the code. Oh, wait, I'm getting an error. "The constructor OpenSimplexNoise noise is undefined." Why am I getting that error? Because I have a constructor OpenSimplexNoise-- oh! It needs this thing, PApplet theParent. Ah-ha! What this is and how this works, PApplet theParent, is probably something I should tackle or address in maybe a third part or a fourth part to this series because I don't think that I need it for this particular OpenSimplexNoise library. But this is a way of having the library know something and communicate to or execute functions in the user's sketch itself. It's not something I initially need for OpenSimplexNoise, but let me just keep it in here for right now. I'll decide later if I can remove it. But there's-- this is not a flaw of the library design. It's now a flaw of my code where I need to say "this." The keyword "this" in Java refers to "this class," and your Processing sketch is actually a class that's just hidden from you when you're working in Processing itself. So now let me run this. And we could see the negative 320. Why is it negative 320? Because I'm multiplying it by width. So that's right, width is 640. The only noise value I ever get back is negative 0.5, multiplied by width is 320. So now we're building the library and we added our own function to a particular class in the library itself. The next step is let's actually put in the OpenSimplexNoise algorithm. Here is the r-- it's raw source code for Kurt Spencer's 2014 implementation of OpenSimplexNoise in Java. Now, there's a little bit of an unfortunate thing, which this class is also named "OpenSimplexNoise." Again, here I am back to this naming thing. Everything is quite difficult, but let's-- let me first just bring this into Eclipse. So there's a variety of ways I could do that, but I'm just going to copy paste it. So I'm going to make-- here, I'm going to create a new class. And I'm going to call it "OpenSimplexNoiseKS," the KS for Kurt Spencer's. I want to keep that implementation entirely intact. So I'm going to hit Finish. I am going to paste it in, and then I am going to hit Save. And then, I need to change this to KS. I need to add the package declaration. And then, I need to find other things. Like, this should be KS, this should be KS, this should be KS, this should be KS. There we go. Now that I have the OpenSimplexNoise original implementation from Kurt Spencer as a separate class here in my library, I have a decision to make. Ultimately, what I want is for that functionality to appear in my OpenSimplexNoise class. And so I could extend the OpenSimplexNoiseKS class, that would be known as inheritance. Or I could really just wrap it by making an object in here, like OpenSimplexNoiseKS generator that is an instance of Kurt Spencer's OpenSimplexNoise implementation. And this is referred to as composition, maybe like wrapping another class as an instance inside of a class. So the reason why I want to do this is I'm trying to-- I'm not trying to expose the full implementation and just add a few window dressing things to it. Although, that would be a legitimate way of designing this library. But I'd rather do it this way just to really hide that, but have my own set of functions that make use of the implementation there. So I'm going to do that here. And then, so in the constructor, I need to create a generator equals new OpenSimplexNoiseKS. And then, in this value function-- and I don't need this say hello function. The welcome function is maybe nice to have. This set-- I'm going to get rid of the set variable and get variables. Those are all just template functions. But what I want to do now is, instead of returning to some arbitrary number, I want to return the generator. And the function inside of the OpenSimplexNoise is called "eval." So maybe I'm actually going to call this "noise." And the function's called "eval." So I'm going to pass X offset to eval. (CHUCKLING) The thing is, the eval-- the OpenSimplexNoise implementation doesn't allow for one dimension. But for me to get one dimension, I could always just pass as the second argument a zero. So why do I have an error here? Let's look at what this error might be. "Cannot convert from double to float." Oh, right! Because OpenSimplexNoise implementation is all done with doubles, but processing and simplification only works with floats. So here's where I can now change this to be a float. And there we go. So now I have essentially wrapped the general-- the eval function, which works in two dimensions, to work in one dimension with floating-point numbers. And now, if I rebuild the library, go back to Processing, and I'm going to run this. Oh, and it's called "noise" now. I renamed it from "value" to "noise." So this circle is disappearing off the screen because I'm getting negative numbers. The built-in noise implementation and processing always gives you a value between 0 and 1, where as this OpenSimplexNoise implementation gives you a value between negative 1 and 1. So there's probably some advantages for me keeping that range between negative 1 and 1. But if I want to make the case that what I want people to be able to use this for is to have their current Processing code just work out of the box by changing it to the OpenSimplexNoise function, then maybe what I should do is, here, I should actually say-- I'm going to say-- I'm going to just call a remap. I'm going to make a function called "remap," private float-- or, double remap, double val. And what I'm doing is I'm saying "return val plus 1 times 0.5," right? Because a value between negative 1 and 1 would shift between 0 and 2, divided by 2 would shift between 0 and 1. So I'm going to do that. So I could rebuild and test this, but I'm pretty sure that correction will work. Let's now add functions for 2D, 3D, and 4D noise to make sure those work as well. So I'm going to do this. (CHUCKLING) I'm just going to do this a few more times. Then, I'm going to add a Y offset. I'm going to add a Y offset and a Z offset. And then, I'm going to add a Y offset, a Z offset, and a U offset. And so this would be xoff, yoff. And, again, I could refactor this to probably have them call each other, but I think this will work fairly well for me. And then, here. So now we have 1D, 2D, 3D, and 4D noise. And I also should add a constructor, which allows me to pass in a seed. So I'm going to say "int seed." And I'm going to pass that seed to OpenSimplexNoise. And with no seed, maybe I'll change it to just call the other constructor "this" with theParent and a System.currentTimeMillis. So I'll use that as the seed. Ah, so I have an error here. Whoops. Oh, it's because currentTime.Millis is a long data type. So maybe I'll change this to long. I think that's probably OK, because you can always give it an integer. And so there we go. So now I have two constructors. If I just say "OpenSimplexNoise this," it'll pick a random seed or I can give it a specific seed, and it'll generate with that seed. So now I'm done [CLAPS] with the basic functionality of this library that I wanted to build. So let's go back and build it again. So people who are watching this live right now in the chat are rightfully complaining about my redundant duplicated code here. At a minimum, let me refactor this to just have the first 1D noise function. Just return this.noise X offset, 0. I do think that the implementations, as you get to higher dimensions, run more slowly. So I don't actually want to call those with fixed dimensions, but I only want to do that for the first one. So, again, I'm sure there's a way to optimize or refactor that. It'll come later in the building this library, but I just want to get it to work. Let me rebuild the library one more time. Go back to Processing, and run it. There we go. The same exact example, but now with OpenSimplexNoise. I'm going to hit Save. And I'm actually going to now make this one of the examples. Whoops. So I'm going to call this, "OpenSimplex-- "OSNoise1D." And then, I'm also going to save this as "OSNoise2D." Let's also go and grab Noise2D. And we're going to Sketch, Import Library, OpenSimplexNoise for Processing. I'm going to make a OpenSimplexNoise noise instance. I going to say "noise equals new OpenSimplexNoise noise this." Then, here I'm going to say "noise.-- oh, let's call this "OSNoise." And I'm going to say, osnoise noise. And let's run this. Look, the same exact example, but with OpenSimplexNoise! Change this to regular noise and run it. It looks like this. Change this to "improved." What I would say is improved OpenSimplexNoise, and it looks like this. So that's another example. And so now, you'll see, by the way, in Eclipse, you can see that the examples are showing up here. And I can get rid of this hello example because I don't need that. I finally have a fully functioning, working version of the library with two examples. Here's the thing. There's a lot more work for me to do. I haven't added anything in the code comments that will help generate documentation for the library. I haven't published a library in a way that it would show up here under Import Library, Add Library in this actual list here. This is a way of publishing it to the Processing list of libraries itself. But this is a good stopping point, because now I'm at a point where you, the viewer, could actually use this library. So I will come back and do a third video about cleaning up and finalizing and publishing the library in a more public way. But right now what I'm going to ask of you, the viewer, is two things. Number one, go and download and try this library yourself. So I'm going to compress this folder and make a file called "OpenSimplexNoise for noise Processing.zip." And I will add a link to the GitHub repo. Here is the GitHub repo for the library. If you go here, the link to this is in the video's description. By the time you're watching this, there will be more information in this README about how to get your hands on this zip file and manually install it to your Processing download. So you can test the library. You can give me feedback by filing an issue here on GitHub. No issues have been filed yet. And you could also contribute to the functionality of this and documentation of this library. So if you have some time and would like to work out filling out this JSDoc, information inside the source code itself. If you really don't like the way (CHUCKLING) I've written these four noise functions and want to refactor that, we can think about and have a discussion about the API design decisions. And after I let that cook for a little while, I'll come back and do a third video to show you these updates, what kinds of changes I've made, and how to take that final last step to creating a website and publishing your Processing library to a website, and having it appear in the Processing contributions manager itself. All right, [CLAPS] I hope this has been helpful to you. I look forward to seeing this project grow. We can add some other noise algorithms to it. There's going to be a lot of fun in creating this open-source project as a Coding Train community and adding it to Processing itself. Thanks for watching, and I'll see you sometime soon in the third part to the series. Goodbye! [TRAIN FLUTE SOUND] [THEME MUSIC]
B1 中級 加工(Java)ライブラリの作り方 その2 (How to Make a Processing (Java) Library Part 2) 1 0 林宜悉 に公開 2021 年 01 月 14 日 シェア シェア 保存 報告 動画の中の単語