반응형
BSP Tree FAQ

ftp://ftp.sgi.com/other/bspfaq/faq/bspfaq.html#2.txt


BSP Tree Frequently Asked Questions (FAQ)


Indexed Listing

    An indexed version of this document is available for those who prefer faster loading.

Questions

  1. CHANGES
  2. ABOUT THIS DOCUMENT
  3. ACKNOWLEDGEMENTS
  4. HOW CAN YOU CONTRIBUTE?
  5. ABOUT THE PSEUDO C++ CODE
  6. WHAT IS A BSP TREE?
  7. HOW DO YOU BUILD A BSP TREE?
  8. HOW DO YOU PARTITION A POLYGON WITH A PLANE?
  9. HOW DO YOU REMOVE HIDDEN SURFACES WITH A BSP TREE?
  10. HOW DO YOU COMPUTE ANALYTIC VISIBILITY WITH A BSP TREE?
  11. HOW DO YOU ACCELERATE RAY TRACING WITH A BSP TREE?
  12. HOW DO YOU PERFORM BOOLEAN OPERATIONS ON POLYTOPES WITH A BSP TREE?
  13. HOW DO YOU PERFORM COLLISION DETECTION WITH A BSP TREE?
  14. HOW DO YOU HANDLE DYNAMIC SCENES WITH A BSP TREE?
  15. HOW DO YOU COMPUTE SHADOWS WITH A BSP TREE?
  16. HOW DO YOU EXTRACT CONNECTIVITY INFORMATION FROM BSP TREES?
  17. HOW ARE BSP TREES USEFUL FOR ROBOT MOTION PLANNING?
  18. HOW ARE BSP TREES USED IN DOOM?
  19. HOW CAN YOU MAKE A BSP TREE MORE ROBUST?
  20. HOW EFFICIENT IS A BSP TREE?
  21. HOW CAN YOU MAKE A BSP TREE MORE EFFICIENT?
  22. HOW CAN YOU AVOID RECURSION?
  23. WHAT IS THE HISTORY OF BSP TREES?
  24. WHERE CAN YOU FIND SAMPLE CODE AND RELATED ONLINE RESOURCES?
  25. REFERENCES


반응형
반응형

http://research.microsoft.com/en-us/um/people/hoppe/pm.pdf



progressive mesh.pdf


반응형
반응형

http://www.gamasutra.com/view/feature/3177/subdivision_surface_theory.php



Subdivision Surface Theory



At Siggraph '98, Pixar unveiled a short animated film. Christened Geri’s Game, it was, to quote its Academy Award press release, the “endearing tale of an aging codger who likes to play chess in the park against himself.” Not only was it artistically stunning, but it was also a technological powerhouse. The short served as a vehicle to demonstrate Pixar’s latest addition to its production environment, a surface scheme known as subdivision surfaces.

Subdivision surfaces are a way to describe a surface using a polygonal model. Like the polygonal model, the surface can be of any shape or size — it’s not limited to a rectangular patch. Unlike that polygonal model, the surface itself is perfectly smooth. Subdivision surface schemes allow you to take the original polygonal model and produce an approximation of the surface by adding vertices and subdividing existing polygons. The approximation can be as coarse or as detailed as your needs allow. Because Pixar’s rendering system requires everything to be broken into polygons that are a half-pixel across, subdivision surfaces allowed them to tessellate automatically to that level everywhere. As such, the artists didn’t need to worry about how close Geri was to the camera. While your game probably can’t quite deal with half-pixel polygons, whatever size you do choose, your models can scale up and down in polygon count with the speed of the machine and their distance from the camera.

Along with Pixar’s work, quite a few researchers are actively tackling issues in the area of subdivision surfaces, and several Siggraph papers each year advance them academically and put them to use in solving problems. By now, they are a fairly mature technology, and a compelling contender among scalability solutions.The technology itself is, for the most part, not new, but its application up until recently has been fairly limited. Indeed, Geri’s Game is still one of the only compelling demonstrations of subdivision surfaces. Nonetheless, it brought attention to subdivision surfaces as a relatively new, up-and-coming technique for implementing scalable geometry.

The game development community realizes that scalable geometry techniques are an important part of developing next-generation game engines. The spread between high-end and low-end hardware seems to get bigger each year (thanks to current and forthcoming geometry accelerators such as Nvidia’s GeForce 256 and S3’s Savage2000), forcing game developers to find ways to cater to the masses that use low-end machines while building in features that make the most of hardcore gamers’ advanced hardware. As a result, on the low end our engines should still be capable of using fewer than 10,000 polygons per scene, but on the high end, the sky’s the limit: even hundreds of thousands of polygons per scene can cruise along at 60 frames per second. Scalable geometry techniques such as subdivision surfaces are therefore necessary to accommodate this variation in hardware capabilities.

In this article, a number of different kinds of subdivision surfaces will be discussed. As a preliminary warning, this article is entirely theory. Next month, we’ll look at an example implementation of one of the schemes, the modified butterfly, which I’ll discuss here. Keep in mind as you read this article that not every concept described here will be practical for use in your engine. Indeed, some subdivision surface models may not be feasible for use in games at all. But knowing the strengths and weaknesses of the various models will help you make the right decision for your next game.

The What and the Why

First, what is a subdivision surface? The obvious answer is that it’s a surface generated through subdivision. To elaborate, every subdivision surface starts with an original polygonal surface, called a control net. Then the surface is subdivided into additional polygons and all the vertices are moved according to some set of rules. The rules for moving the vertices are different from scheme to scheme, and it is these rules that determine the properties of the surface. The rules of most schemes (including all the ones discussed here) involve keeping the old vertices around, optionally moving them, and introducing new vertices. There are schemes that remove the old vertices at each step, but they’re in the definite minority.

The one thing the control net and the eventual surface (called the limit surface) have in common is that they are topologically the same. Topology is a way of describing the structure of a surface that isn’t changed by an elastic deformation, that is, a stretching or twisting. A good example and common joke is that to a topologist, a coffee cup and a donut are identical. The donut hole corresponds to the hole in the handle of the coffee mug. On the other hand, a sphere and coffee mug are not topologically equivalent, since no amount of stretching and twisting can punch a hole in that sphere.

Topology is one reason that subdivision surfaces are worth a look. With Bézier or B-spline patches, modeling complex surfaces amounts to trying to cover them with pieces of rectangular cloth. It’s not easy, and often not possible if you don’t make some of the patch edges degenerate (yielding triangular patches). Furthermore, trying to animate that object can make continuity very difficult, and if you’re not very careful, your model will show creases and artifacts near patch seams.

That’s where subdivision surfaces come in. You can make a subdivision surface out of any arbitrary (preferably closed) mesh, which means that subdivision surfaces can consist of arbitrary topology. On top of that, since the mesh produces a single surface, you can animate the control net without worrying about seams or other continuity issues.

As far as actual uses in games, I believe that subdivision surfaces are an ideal solution for character modeling. Environments and other parts of a game generally don’t have the fine detail or strange topology that would require subdivision surfaces, but characters can have joint areas that are particularly hard to model with patches, and characters are in constant animation, which makes maintaining continuity conditions very important.

The basics. Before we start discussing individual schemes, let’s look at the basic characteristics of subdivision surfaces in general. This gives us a framework for classifying and comparing the schemes as we come across them. Most of these characteristics carry notable implications with them, whether they are implied computational costs or implied ease-of-use considerations, or anything else. These will usually be the criteria on which you might choose one scheme above another.

Continuity: the holy grail. The first characteristic of a scheme is its continuity. Schemes are referred to as having Cn continuity, where n determines how many derivatives are continuous. So if a surface is C0 continuous, it means that no derivatives are continuous, that the surface itself doesn’t have open holes. If a surface is C1 continuous, it means that the surface is closed and that its tangents are continuous (so there aren’t any sharp seams).

This probably won’t be a major selling point of one scheme above another, since just about every scheme has C1 continuity everywhere. Some have C2 continuity in some places, but the majority have areas where the best they can claim is C1. So most schemes are alike in this regard.

However, continuity is most certainly worth mentioning because it’s one of the major reasons to think about using subdivision surfaces in the first place. After all, Pixar could have modeled Geri using as many polygons as they wanted, since they’re not running their movies in real time. But no matter how many polygons they used, you could get close enough that Geri’s skin would look faceted from the polygons. The point of using a subdivision model is that you have that ideal limit surface at which you can always throw more and more polygons as you get closer and closer to, no matter how high the display resolution or how close the model is to the screen. Only a very small portion of the real world is flat with sharp edges. For everything else, there’s subdivision surfaces.

To Interpolate or not to Interpolate...

While the degree of continuity is generally the same for all subdivision schemes, there are a number of characteristics that vary notably between schemes. One important aspect of a scheme is whether it is an approximating scheme or an interpolating scheme. If it’s an approximating scheme, it means that the vertices of the control net don’t lie on the surface itself. So, at each step of subdivision, the existing vertices in the control net are moved closer to the limit surface. The benefit of an approximating scheme is that the resulting surface tends to be very fair, having few undulations and ripples. Even if the control net is of very high frequency with sharp points, the scheme will tend to smooth it out, as the sharpest points move the furthest onto the limit surface. On the other hand, this can be to the approximating scheme’s detriment, too. It can be difficult to work with, as it’s harder to envision the end result while building a control net, and it may be hard to craft more undulating, rippling surfaces as the scheme fights to smooth them out.

Figure 1. Two schemes subdivide a 
tetrahedron. The left scheme is 
approximating, and the right is interpolating.

If it’s an interpolating scheme, it means that the vertices of the control net actually lie on the limit surface. This means that at each recursive step, the existing vertices of the control net are not moved. The benefit of this is that it can be much more obvious from a control net what the limit surface will look like, since the control net vertices are all on the surface. However, it can sometimes be deceptively difficult to get an interpolating surface to look just the way you want, as the surface can develop unsightly bulges in areas where it strains to interpolate the vertices and still maintain its continuity. Nonetheless, this is usually not a tremendous problem.

Figure 1 shows examples of an approximating scheme (on the left) and an interpolating scheme (on the right). The white outline is the control net, and the red wireframe is the resulting surface after a few subdivision steps. You can see the difference quite clearly: the approximating surface seems to pull away from the net, while the interpolating surface flows through the vertices of the net.

Surfaces in Uniform

Another set of characteristics of a scheme brings in four more terms. A scheme can be either uniform or nonuniform, and it can be either stationary or nonstationary. These terms describe how the rules of the scheme are applied to the surface. If the scheme is uniform, it means that all areas of a control net are subdivided using the same set of rules, whereas a nonuniform scheme might subdivide one edge one way and another edge another way. If a scheme is stationary, it means that the same set of rules is used to subdivide the net at each step. A nonstationary scheme, on the other hand, might first subdivide the net one way, and then the next time around use a different set of rules.

All the schemes we’ll talk about here are fundamentally both uniform and stationary. There are some extensions to these schemes that make them nonstationary or nonuniform, but there aren’t many subdivision schemes that are fundamentally nonstationary or nonuniform. One of the main reasons for this is that most of the mathematical tools we have for analyzing schemes are unable to deal with dynamically changing rules sets.

Subdivision Shape

Another characteristic of a scheme, albeit less significant than the prior ones, is whether it is triangular or quadrilateral. As the names would imply, a triangular scheme operates on triangular control nets, and a quadrilateral scheme operates on quadrilateral nets. Clearly, it would be inconvenient if you had to restrict yourself to these primitives when building models. Therefore, most quadrilateral schemes (including the one discussed here) have rules for subdividing n-sided polygons. For triangular schemes, you generally need to split the polygons into triangles before handing them over to be subdivided. This is easy enough to do, but one downside is that for some schemes, the way you break your polygons into triangles can change the limit surface. The changes are usually minor, though, so you simply need to be consistent: if you randomly choose which diagonal of a quadrilateral to split on every frame, you’ll end up with popping artifacts.

Figure 2 shows examples of a triangular subdivision scheme as compared to a quadrilateral scheme. Notice that the triangular scheme only adds new vertices along the edges, whereas the quadrilateral scheme needs to add a vertex in the center of each face. This is one reason why triangular schemes tend to be somewhat easier to understand: their rules have that one fewer step in them.

Figure 2. The differences between the tessellation used by a triangular scheme (top) and a quadrilateral scheme (bottom).

Extraordinary Vertices

The preferred vertex valence is another property of subdivision schemes. The valence of a vertex is the number of edges coming out of it. Most every vertex a scheme produces during subdivision has the same valence. Vertices of that valence are the regular vertices of a scheme. Vertices of any other valence are known as extraordinary vertices. Their effect depends on the subdivision scheme, but historically there have been problems analyzing the limit surface near extraordinary vertices. As we look at various schemes, we’ll see the effect that extraordinary vertices have on each one.

Most schemes don’t ever produce extraordinary vertices during subdivision, so the number of extraordinary vertices is set by the original control net and never changes. Figure 3 is an example of two steps of a triangular scheme with an extraordinary vertex in the center. Notice how it remains the only extraordinary vertex after a step of subdivision. Also note that the valence of the regular vertices is 6. This is common for triangular schemes, as they all tend to split the triangles in the same way — by adding new vertices along the edges and breaking each triangle into four smaller triangles.

Figure 3. A triangular net (left) and after one subdivision step (right). The red vertex is extraordinary.

Surface Evaluation

Surface evaluation is the process of taking a control net, adding vertices, and breaking faces into more, smaller faces to find a better polygonal approximation of the limit surface. There are a number of ways to evaluate a subdivision surface. All subdivision schemes can be evaluated recursively. Furthermore, most (including all the ones discussed here) can be explicitly evaluated at the vertex points of the control net. For interpolating schemes, this means that you can explicitly calculate the surface normals at the vertices using what are called tangent masks. For approximating schemes it means you can also explicitly calculate the vertex’s limit position, using what are called evaluation masks. In this context, a mask isn’t the same kind of mask that you might use during binary arithmetic. Our masks are more analogous to the masks worn at a masquerade. They are like stencil cutouts, shapes that can be “placed” on the control net, and their shape determines which of the surrounding vertices are taken into account (and how much effect each has) in determining the end result, be it the vertex location or its tangent vectors. Figure 4 shows a visual example of applying a mask to a surface at a vertex.

Figure 4. A hypothetical mask. Here, the white region is a mask used to dictate which vertices are used in a computation involving the 
red vertex.

An important aspect of evaluation is the scheme’s support. The support refers to the size of the region considered during evaluation. A scheme is said to have compact support if it doesn’t have to look very far from the evaluation point. Compact support is generally desirable because it means that changes to a surface are local — they don’t affect the surface farther away.

A Note on Notation

Since the original authors of many subdivision schemes weren’t operating in concert with one another, the notation used between schemes tends to vary fairly wildly. Here, I’ve tried to stick with a fairly consistent notation. When talking about a specific vertex, it is v. If it matters what level of recursion it’s at, that level i is indicated as a superscript, so the vertex is vi. The vertex’s valence is N. The neighboring vertices of the vertex are ej where j is in the range [0,N–1]. Again, if the level of recursion matters, that level i is a superscript, so eij is the jth edge vertex at level i. I try to use this notation everywhere, but there are a few places where it’s much clearer to use a different notation.

The one problem with a standard notation is that if you access some of the references at the end of this article, they will very likely use their own, different notation. As long as the concepts make sense, though, it shouldn’t be difficult to figure out someone else’s naming convention.

The Polyhedral Scheme

The polyhedral scheme is about the simplest subdivision scheme of all, which makes it a good didactic tool but not the kind of scheme you’d ever actually want to use. It’s a triangular scheme where you subdivide by adding new vertices along the midpoints of each edge, and then break each existing triangle into four triangles using the new edge vertices. A simple example is shown in Figure 5. The problem with this, of course, is that it doesn’t produce smooth surfaces. It doesn’t even change the shape of the control net at all. But it serves to demonstrate some concepts fairly well.

Figure 5. Two steps of subdividing a 
triangle with the polyhedral scheme.

The scheme is clearly interpolating since it doesn’t move the vertices once they’re created. It’s also triangular, since it operates on a triangular mesh. Furthermore, the scheme is uniform since the edge’s location doesn’t affect the rules used to subdivide it, and stationary since the same midpoint subdivision is used over and over. The surface is only C0 continuous, since along the edges of polygons it doesn’t have a well-defined tangent plane. The regular vertices of this scheme are of valence 6, as that’s the valence of new vertices created by the scheme. However, this scheme is simple enough that it doesn’t suffer because of its extraordinary vertices.

The evaluation of the scheme isn’t hard at all. You can evaluate it recursively using the subdivision rules. As far as evaluation and tangent masks go, it’s clear that we don’t need an evaluation mask, since the points are already on the limit surface. Tangent masks don’t really make any sense, since our surface isn’t smooth and therefore doesn’t have well-defined tangents everywhere.

Figure 6 shows a tetrahedron control net in white with a red wireframe of the surface after a few subdivision steps of the polyhedral scheme.

Figure 6. A tetrahedron 
control net (in white) and 
a polygonal surface approximation (in red) produced using the 
polyhedral scheme.



반응형
반응형

http://misofruit.co.kr/seojewoo/programming/project2312.htm



지형 처리 방법

3D게임의 가장 큰 특징은 가상의 공간을 자유롭게 돌아다닐 수 있다는 데서 찾을 수 있다. 따라서 대개 3D 게임은 
굉장히 큰 공간을 배경으로 진행되는 경우가 많다. 그런데, 공간이 커지면 커질수록 동시에 처리해야 하는 데이터의
양도 급증해 컴퓨터가 감당할 수 없을 정도의 부하를 주게 된다. 이러한 이유로 3D게임에는 효율적인 공간 처리방법
들이 연구되고 구현돼 왔지만, 모든 경우를 자유롭게 처리할 수 있는 이상적인 방법은 없고 제작하려는 게임에 가장
적절한 방법을 선택해 구현하는 것이 현명하다. 여기서 소개하는 방법은 가장 널리 사용되고 있으며 효율도 우수하
지만 사전 작업의 시간을 많이 필요로 하므로 정적인 지형의 경우에 알맞다.



BSP

BSP는 Binary Space Partition의 약자로, 말 그대로 이분적인 공간 분할 방법을 의미한다. 큰 지형을 이진트리 형태
호 분석해 노드 정보를 구성하고 이를 참조해 대상 물체를 찾아내는 것이 BSP의 기본 원리로, 유명한 돔에서 사용한
이후로 널리 알려졌다. BSP는 간단하게 다음과 같은 과정으로 실시된다.

(1)모델에 존재하는 면 중 하나를 선택한다. 만약 선택할 면이 없으면 종료한다.

(2)선택한 면의 위에 겹치는 모습의 무한 평면을 상상해 이것으로 공간을 분할한다. 이 때 무한 평면에 걸치는 면이
    있으면 이것은 두 개로 잘라진다.(이미 처리된 면은 생략).

(3)선택한 면의 법선 방향을 앞으로, 반대방향을 뒤로 해서 앞쪽에 있는 면들에 대해 (1)의 과정을 제귀적으로 수행
    한다.

(4)선택한 면의 뒤쪽에 있는 면들에 대해 (1)의 과정을 재귀적으로 수행한다. 이 과정을 실제의 예를 들어 설명해보
    겠다.





<그림 8 >과 같은 지형이 있고, 이것을 BSP를 이용해 <그림9 >처럼 분할해보자.
우선 임의의 한면을 선택한다. 여기서는 10면을 선택한다. 그러면 이것은 최상위 노드에 위치하고, 이 평면을 중심
으로 앞뒤로 분할하게 된다. 면의 앞쪽에 있는 면들은 왼쪽 노드에 속하고, 뒤쪽은 오른쪽 노드가 된다.
이때 분단면이 관통하는 5면은 분할돼 각각 5a/5b로 나눠진다. 이제 분할된 면을 기준으로 (1)의 과정을 반복한다.

이번에는 3면을 선택해 수행한다. 이때 주의할점은 이미 처리된 면이나 부모 노드가 다른 쪽은 대상에서 제외된다는
것이다. 우선 앞 노드에 대해 앞의 과정을 재귀적으로 계속 처리하고 완료하면 다시 최상위의 뒤쪽 노드에 대해서도
같은 식으로 적용한다. 그러면 <그림 10>과 같이 BSP노드 정보가 완성된다.



마지막에 위치한 노드는 최종적으로 존재할 수 있는 노드로서 이 노드의 안쪽에 있으면 지형 내에 존재하는것으로
판단된다. NULL노드에 위치하거나 최종 노드의 바깥쪽에 있으면 지형을 벗어나는 것으로 간주한다. 이제 이러한 
정보를 갖고 임의의 위치나 지형 안에 포함되는지를 검사해보자.


 

<그림 12 >처럼 별표의 위치에 게임의 캐릭터가 존재한다고 가정할 때 BSP노드의 정보를 따라 검색하면, 우선 지
정된 위치는 10면의 뒤쪽 -> 6면의 뒤쪽 -> 9a면의 앞쪽 -> 5b면의 앞쪽이라는 방식으로 도형안에 속해 있음을 알
수 있다. BSP트리 생성의 과정을 C++로 작성하면 다음과 같다.

BspNode * BSP :: Make(Model * pModel )
      //노드 생성
      BspNode *pNode = new BSP_Node( );
      //모델에서 분단면으로 쓸 폴리곤 선택
      Polygon *pPolygon = pModel- >GetPartitionPolygon();
      //더이상 분할할 수 없는 경우
      if ( pPolygon ==NULL ) return node;

      //분단면을 트리 구조에 보존
      pNode -> SetPartitionPlane ( pPolygon );
      //선택한 면으로 모델을 이등분
      Model *pFront, *pBack ;
      pFront = SplitFrontModel (pModel, pPolygon);
      pBack = SplitBackModel (pModel, pPolygon);

      //BSP 트리를 만들기 위해 재귀적으로 분할해 트리에 추가
      pNode->LinkToFront ( Make ( pFront ) );
      pNode->LinkToBack ( Make ( pBack) );

이러한 방식으로 BSP를 이용하면 복잡한 지형도 검사 대상을 획기적으로 줄여 짧은 시간 내에 처리할 수 있고,깊이
정렬이 자동적으로 이뤄져 렌더링 속도가 빨라지는 효과도 누릴 수 있다.

반응형
반응형

http://talkon.egloos.com/1222472



dPVS 상용로 판매되는 라이브러리 같다. 동작 방법은 버퍼에 씬정보를 가지고 있으면서 오브잭트가 그려질지 안그려질지를 결정하면서 컬링이 이루어 지는 방식이고 순서는 다음과 같다.


1. Occlusion Buffer를 만든다. (frame, zbuffer or stencil)

2. View Frustum으로 Object를 컬링한다.

3. 컬링되고 남은 오브잭트는 가까운 것에서 먼 곳 순으로 정렬해준다.

4. 그려야할 오브잭트가 버퍼와 비교해 렌더링 하고 갱신한다.


기본적인 개념은 위와 같이 진행된다.

으음... 



http://www.gpgstudy.com/forum/viewtopic.php?p=9888


Hierarchical Occlusion Map (HOM) 란 놈도 있는데 이 놈은 어떨지...



반응형
반응형

http://www.misofruit.co.kr/seojewoo/programming/project23111.htm




PVS(Potentially visible set)은 visible surface determination(보이는 면 결정)알고리즘의 하나이다. 공간상에서 폴리곤들은 다른 폴리곤에 가려서 보이지 않는 경우가 많다. 그래서 보이는 폴리곤들만을 결정해서 렌더링한다는 이론이다. 퀘이크엔진의 경우, 지형을 leaf라고 하는 여러 개의 영역으로 나눈 뒤(leaf를 방이라고 생각하면 이해가 쉬울 것이다.) 각 영역에서 보일 수 있는 영역들의 리스트(potentially visible set: PVS)를 미리 계산하여서 Lookup 테이블에 저장해 둔다. 게임 동작중에는 카메라의 위치에 따라 해당 위치의 leaf에서 보이는 영역에 대한 리스트를 Lookup테이블을 참조하여서 얻을 수 있다. 그리고 이 영역들만을 렌더링하게 되고 나머지 leaf들은 렌더링에 포함되지 않는다.

감자님의 사이트에 올려져 있는 글입니다.
http://www.gamza.net/ez2000/ezboard.exe?db=Algorithm&action=list&page=0 

** Portal을 이용한 PVS작성개념 **
copyrightⓒ 김성수 [2001년 02월 21일]

퀘이크가 '보이는 공간 작성'에 사용하는 방법은? 포탈 입니다. 
포탈은 두개의 공간과 연결되어있고, 공간은 여러개의 포탈과 연결될수 있죠. 
퀘이크가 하는짓은...궤이크 유틸소스/Vis/flow.c 의 void RecursiveLeafFlow (...) 만 분석해보시면 됩니다. 
개념을 잡기위해 간단하게 그림을 몇장 그려봤습니다.

공간 A에서 보이는 공간리스트를 작성하기 위한 그림입니다.
우선 공간A의 임의의 포탈Pab와 그와 연결된 공간 B의 Pab가 아닌 임의의 포탈Pbc를 잡습니다.
Pbc와 연결된 또다른 공간을 C라하고 Pab위에서 Pbc를 통해 보이는 C의 포탈을 찾습니다.
이때 일부만 보이는 포탈은 클리핑을 합니다.








이 과정을 재귀적으로 반복하여 더이상 보이는 포탈이 없을때까지 반복을 하면 됩니다.
아래 그림은 한 공간내에 포탈이 두개 이하이지만...보통은 그 이상이될경우가 많습니다.
이때는 모든 포탈에대해 하나도 빠짐없이 똑같은 일을 수행한다고 생각하시면 됩니다.


이 그림에서는 Pab를 통해 보이는 포탈이 Pbc, Pcd, Pde뿐이니...보이는 공간리스트는.. B,C,D,E 가 되겠네요.

자세한 해답은 '궤이크 유틸소스/Vis/flow.c' 에 있습니다.
재귀호출이 마구 난무하고있는 소스라 분석이 매우 어렵지만... 
열심히 보시면 이해가 되리라 생각됩니다. 설명은...그냥 참고 정도로만 생각하시구... 

참...퀘이크 유틸소스는...BSP트리구성시 유의할점들... 에 포함되어 있습니다.

                 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

다음은 마소 2001년 9월호에 올라와 있는 글이다.


 

반응형
반응형

일어라 구글 번역..



http://www.kotaku.jp/2013/01/cry_engine_mine_craft.html


'마인 크래프트' (영상)


깨끗 너무 샌드 박스


나는 차를 불었다 구?

조금 복고풍 디자인으로 사랑 받고있는 인기 모형 정원 게임 " 마인 크래프트 "를 최신 게임 엔진 으로 만들어되면 어떻게 될까요? 

해외 게시판 "Reddit"사용자가 게시 한 CryEngine3 바람 마인 크래프트 의 이미지를 아래에서 참조하십시오.
 

CryEngine3 바람 마인 크래프트


뭐라고하는 것입니다 ... "마인 크래프트"의 묘미이기도하다 레트로 감각 이 없어져 버렸습니다. "이런 내 사랑 주자 인이 아니다!"라고 생각하는 사람도 있겠지만, 이것은 어디 까지나 이미지 그림이므로 안심을.

깨끗한 그래픽 노는 것도 즐거울지도 모릅니다 만, 역시 '마인 크래프트'는 그 독특한 복고풍 느낌이 중요한구나 새삼 느꼈습니다.



이쪽은 인기 해외 RPG " The Elder Scrolls V Skyrim "과 같은 그래픽 '마인 크래프트'를 재현 한 오리지널 게임 같이 캐나다인이 운영하는 블로그 'Procedural World"에 공개되어 있습니다. 그 밖에도 동영상을 공개하고 있으므로, 흥미를 가진 사람은 보러 가보니 좋은지도 모릅니다.


Procedural World : Sandbox Mode [YouTube] Into the sandbox [Procedural World] This is what a next-generation version of Minecraft could look like [GSOGaming]

반응형
반응형


다음




이전
다음






이전
다음





반응형
반응형

참고)

http://en.wikipedia.org/wiki/Convex_hull

요렇게 stage에 무작위로 찍은 점들이 있다치자.

원기둥 쯤으로 생각하고 원기둥들을 실로 감싸면 아래 그림처럼 될 것이다. 가운데쯤 있는 원기둥은 강력접착제로 붙이지 않고는 차례가 돌아가지 않을 것이다.

위 원기둥이 그저 눈에 보이라고 그려 놓은 것이고 크기가 없는 점이라고 하면 다음과 같이 될 것이다.

오목한 부분이 없는 폴리곤 형태다. 그래서convex hull이라 부르는게 아닐까 싶다.

기하알고리즘들이 그렇듯 눈으로 보면 대충 알겠는데 이걸 코드로 바꾸려면… 어렵다.

Convex hull관련 알고리즘도 굉장히 여러가지가 있고 그럭저럭 쉽게 이해한 Graham Scan 방식을 설명해보려한다.

  1. 첫 시작점을 어떤걸로 정할지
  2. 둘러칠 점의 순서는 또 어떻게 정할지
  3. 요 점이 내부에 포함될 점인지 아니면 외곽에 해당하는 점이지는 어떻게 알아낼지

3가지가 핵심이다.

GrahamScan은 시작점과 다른 모든 점이 이루는 각도를 가지고 가장 작은 각에서 가장 큰 각을 순서로 선을 잇는다.

시작점은 가장 상하좌우 가장 끝에 있는 걸 고른다.

이렇게 얻은 각도를 로 양의 정수로 고쳐서 소팅하거나 (Math.atan2의 경우 마이너스 값이 나올 수도 있다.)

양의 각도, 음의각도 두개를 따로 소팅한 뒤 합치는 것도 방법일 수 있겠다.

플래시에서는 맨 좌측에 있으면서 가장 위에 있는 녀석을 고르는 것이 각도 구할 때 유리할 것이다. 음의 각도가 나오지 않는다.

선을 이어나가는 방향은 ccw나 cw 한방향을 만족시켜야 되는데... 무슨 말인가 하면:

1번그림처럼 시계방향으로 회전한 다음 시계반대방향으로 회전하게 되면 오목한 부분이 생긴다는 말이다.

2번에서 시계반대방향이 생긴경우 해당 점을 제외시킨다.

3번 그림처럼 다음 점과 방향검사를 한다. 처음 시도한 방향과 같으면 선을 연결한다.

이러한 방향은 두 벡터의 외적으로 쉽게 알 수 있다. 외적의 값이 0이면 collinear(공선벡터: 스칼라 값은 다르더라도 방향이 같다)이고 음수이면 왼쪽(cw:시계방향)으로 돌고 양수이면 오른쪽(ccw:반시계방향)으로 돈다.

그럼 시작점을 찾아보자.

시작점과의 각도를 구한다. (시작점이 원점이 되도록 한다.)







http://blog.naver.com/helloktk/80050600334




주어진  convexhull (counterclockwise)에 임의로 한 점을 추가하여 새로운 convexhull 를 구성하는 procedure 다. 작동의 원리는 아래의 그림과 같다. 만약에 주어진 점이  convexhull 의 내부점이면 원래의 convexhull이 반환된다.

 

 

std::vector<CPoint>
chull_point_merge(CPoint Q, std::vector<CPoint>& chull) {
    std::vector<CPoint> out;

    int n = chull.size();

    if(n < 2) {
        out = chull; out.push_back(Q);
        return  out;
    }

    bool pushed = false;

    bool prev = isright(chull[n-1], chull[0], Q)  ; 
    for(int i = 0; i < n; i++) {
        bool curr = isright(chull[i], chull[(i+1)%n], Q)  ;
        if(prev) {
            if(curr) {
                if(!pushed) {
                    out.push_back(Q);
                    pushed = true;
                }
                continue;
            }
            else if(!pushed) {
                out.push_back(Q);
                pushed = true;
            }
        }
        out.push_back(chull[i]);
        prev = curr;
    } 
    return out;
}

//C is on the right side of segment AB ;
bool isright(CPoint A, CPoint B, CPoint C) {
    B -= A; 
    C -= A;
    return (B.x * C.y - B.y * C.x) < 0   ;
}


반응형
반응형

어딘가에서 뽑아온 그림 기억이 안남..;


반응형
반응형

반응형
반응형

[밀리언 파티클 시스템]

http://210.96.133.182/knowledge/trend/abroad/__icsFiles/afieldfile/2010/05/02/72218.pdf


[파티클 엔진]

http://www4.wittenberg.edu/academics/mathcomp/computer_science/students/student_projects/computer%20graphics/bixler_guthikonda/index.html


[파티클시스템]

http://www.google.co.kr/url?sa=t&rct=j&q=%ED%8C%8C%ED%8B%B0%ED%81%B4%EC%8B%9C%EC%8A%A4%ED%85%9C&source=web&cd=1&ved=0CDQQFjAA&url=http%3A%2F%2Fcfs7.tistory.com%2Fupload_control%2Fdownload.blog%3Ffhandle%3DYmxvZzIwOTc5NEBmczcudGlzdG9yeS5jb206L2F0dGFjaC8wLzEyLnBkZg%3D%3D%26filename%3DClass08.pdf&ei=0c4wT5OHKIueiAfFvIyABQ&usg=AFQjCNHAP0WEevj95zn1t2ZjOwNtkONxUg&sig2=a1O1RjcbZHWnNqlwe-3qVQ&cad=rjt

http://www.google.co.kr/url?sa=t&rct=j&q=%ED%8C%8C%ED%8B%B0%ED%81%B4%EC%8B%9C%EC%8A%A4%ED%85%9C&source=web&cd=10&ved=0CGQQFjAJ&url=http%3A%2F%2Fpds5.egloos.com%2Fpds%2F200705%2F27%2F66%2F(particle_system).ppt&ei=0c4wT5OHKIueiAfFvIyABQ&usg=AFQjCNGKqBsmMz57U45RYXBVF3vrtd6MRg&sig2=mfdAbChMMCHtuImHGcRRzA&cad=rjt


GPU를 이용한 실시간 분수 시뮬레이션을 위한 파티클 시스템

http://visualcomputing.yonsei.ac.kr/papers/domestic/KCC08_sh.pdf


ppt 인데 소스 좀 있는것

http://graphics.pcu.ac.kr/nicesk/DirectX_2/10week/14Particle.pdf

http://www.google.co.kr/url?sa=t&rct=j&q=%ED%8C%8C%ED%8B%B0%ED%81%B4%EC%8B%9C%EC%8A%A4%ED%85%9C&source=web&cd=65&ved=0CEAQFjAEODw&url=http%3A%2F%2Fdis.dankook.ac.kr%2Flectures%2Fgame07%2Fattachment%2F1363750330.pdf&ei=ztYwT72WLaOkiAeft8SVBQ&usg=AFQjCNFFetFktZ4v9UFLaxLaDlxJevXHsA&sig2=bFSOrdtnlJTuSDCppIEvig&cad=rjt

반응형
반응형

http://blog.naver.com/doridori3510/30130730459



* 우연한 계기로. 컴포넌트 기반으로 게임을 설계하는 블로그까지 흘러갔다.

링크 : http://kiro86.egloos.com/661187

이번에 과제를 수행하면서

계속되는 상속의 상속의 상속..

그러다가 새로운 기능이 추가되면.

쓸데없는 부분까지 상속..

아. 코드가 지저분해지고 있어.

게임 개발에서도 보통 이런식의 계층적인 상속 구조로 진행해왔는데.

시간이 갈수록 점점 복잡해지는 게임의 오브젝트들.

나무가 움직이고, 돌이 깨지고.. 등등

그래서 좀더 유지보수와 개발을 편리하게 하기위한 설계의 하나의 방법인

컴포넌트 기반으로 클래스간의 관계를 정립하자.

컴포넌트가 무엇이냐.

그냥 쉽게 하나의 속성(?)으로 생각하면 될듯.

인간 이라는 오브젝트는

걸을 수 있다. ( 컴포넌트 1 )

죽을 수 있다. ( 컴포넌트 2 )

체력이 있다. ( 컴포넌트 3 )

..등등등. ...

다양한 속성을 지니고 있지 않은가.

GPG6 에 있는, 4.6 게임 객체 구성요소 시스템 에 그에 대한 설명이 나와있따.

정리를 해보자면.

GameObject. 하나의 오브젝트 ( 사람, 자동차, 몬스터.. 등등 )

class GameObject

{

map<Component_ID, *Component> 컴포넌트 자료 집합

Add_Component() // 컴포넌트 추가

Remove_Componet() // 컴포넌트 삭제

Get_Component( ID ) // 컴포넌트 ID에 대응되는 컴포넌트 리턴

}

이런식으로,

하나의 오브젝트는 여러개의 컴포넌트들을 추가하거나, 삭제, 인터페이스 Get 을 할수 있어야 겟다.

Component. 하나의 속성 ( 그려진다, 체력이 있다. 움직일 수있다.. )

class Component

{

GameObject* pOwner; // 현재 컴포넌트를 가지고 있는 오브젝트의 포인터를 가지고 있어야 한다.

// 컴포넌트끼리의 의사소통을 위해서.

// Owner 를 통해서, 또다른 컴포넌트를 얻어와야한다.

GetID() // 컴포넌트별로 식별 가능한 고유 아이디

GetFamilyID() // 비슷한 종류의 컴포넌트끼리의 그룹 아이디

}

이런식으로,

컴포넌트는 자기만의 식별 가능한 아이디를 가지고 있어야한다.

책에서는 클래스의 이름을 아이디로 하면, 서로 중복되지않는 고유 아이디를 가질 수 있다고!

패밀리 아이디가 필요한 이유도 있는데.

만약

그릴수 있는 컴포넌트가 있다.

class Component_Render

그리고 원을 그리는 컴포넌트가 있다. 어차피 그리는 컴포넌트니깐. 상위 컴포넌트를 상속 받는다.

class Component_Render_Sphere : public mponent_Render

또, 네모를 그리는 컴포넌트가 있다. 마찬가지로 상속

class Component_Render_Rect : public mponent_Render

이제.

class GameObject_A 가 있다.

근데 이놈은, 어떨경우에는 원을 그리고, 다른경우에는 네모도 그린다.

그렇다면 코드상에서

if( 원 컴포넌트 )

원 컴포넌트 -> Render()

else ( 네모 컴포넌트 )

네모 컴포넌트 -> Render()

이렇게 해야한단 말인가? 말도 안됨.

그래서 책에서는 FamilyID 를 통해서,

공통된 그룹은 그냥 상위 컴포넌트의 인터페이스를 가져와서 하면 된다고.

if( 렌더링 컴포넌트 )

렌더링 컴포넌트 -> Render() // 알아서, 현재 원이라면 원을 그리고, 네모라면 네모를 그리것지.

// 기본 코어는 끝이고.

// 책에서는 추가적으로. 템플릿 팩토리 객체. 를 통해서 컴포넌트와 오브젝트를 생성한다.

객체를 생성하는데 좀더 편하게 만들기 위해서.

각자 컴포넌트, 오브젝트를 생성하는 객체를 만들고.

이 객체들을 생성하는 팩토리 객체를 만들어서.

관리를 한다.

반응형
반응형



water reflection 수면 반사 방법! DirectX

2011/12/15 10:12

복사 http://blog.naver.com/doridori3510/30126259858


수면 반사에 대해 shaderx2 라는 책을보고 했지만 !

쉐이더 코드는 어셈으로 되어있었고ㅜㅜ 하다못해 소스는 컴파일이 안되고ㅜㅜ

삽질하는 경우가 많아서. 정리해본다.

처리 프로세스를 간략하게 정리하자면..

1. 현재 화면을 렌더링 한다.

2. 현재 카메라의 view 매트릭스를 미러링 한다.

3. 미러링된 view로 텍스쳐에 현재 화면을 그린다. ( 단, 수면을 경계로 cliping 한 영역을 그린다 )

4. 그려진 텍스쳐를 쉐이더 코드를 통해서 렌더링한다.

TIP. 카메라를 미러링 하기

그림판으로 대충 그린 그림으로 보고 이해를 하자면.

원본 카메라의 view를 플랜을 기준으로 미러링을 시킨다.

책에서는 자세하게 설명이 되어있는데.

어쨋든 현재 view를 미러링 시키기 위한 matrix를 만들어낼수 있다.

// 반사 매트릭스

D3DXMATRIX mtxReflect;
D3DXMatrixIdentity( &mtxReflect );
mtxReflect._22 = -1.0f;
mtxReflect._42 = 2.0f * WATER_HEIGHT;

현재 카메라의 view를 반사 매트릭스와 곱하면, 미러링된 카메라의 view를 얻을수 있다.

이 view를 셋팅을 하고 장면을 렌더링하면 반사된 장면을 얻을수 있다.

참고사항 :

1. 물을 기준으로 클리핑을 해서 미러 view로 렌더링 해야한다.

클리핑 평면을 셋팅하는데 쉐이더 코드로 메쉬를 그린다면! 평면을 trasform 해주어야 한다.

// 이런식으로 평면을 한번더 Transform 해준후에 디바이스에 셋팅하자.

D3DXMATRIX mtxView = *(pCamera->GetViewMatrix());
D3DXMATRIX mtxProj = *(pCamera->GetProjMatrix());

D3DXMATRIXA16 WorldToProjection = mtxView * mtxProj;

D3DXMatrixInverse(&WorldToProjection, NULL, &WorldToProjection);
D3DXMatrixTranspose(&WorldToProjection, &WorldToProjection);

D3DXPlaneTransform( &m_clip_plane, &m_local_plane, &WorldToProjection );
D3DXPlaneNormalize( &m_clip_plane, &m_clip_plane );

2. 평면을 기준으로 클리핑 할때, 약간 더 실제 평면 아래쪽으로 클리핑해야지 수면과의 경계에서 약간씩 틈이 보이는것을 방지할 수있다. 일명 약간의 꼼수!

< 왼쪽 : 실제 현재 view > < 오른쪽 : 미러 view로 직은 모습 >

TIP. 반사된 장면을 평면에 투영하기

반사된 장면을 찍었는데, 그냥 평면에다가 SetTexture로 그리면 아마 뭔가 좌표값이 안맞아서 이상하게 그려질 것이다. 이 문제로 한 3일간 삽질한것 같은데..

결론은. 평면을 렌더링 할때 텍스쳐의 uv 좌표계를 계산해주어야 한다.

즉, ( 투영 공식 = 미러뷰 * 프로젝션 ) 에서 정점위치를 계산한후에 이를 픽셀 세이더에 넘기고

픽셀에서는 투영된 정점 위치를 기준으로 다시 uv 좌표계를 계산한다.

# 정점 쉐이더

// UV 좌표 계산
o.ReflectPos = mul( float4( Pos, 1.0f ) , g_mWorld );
o.ReflectPos = mul( o.ReflectPos , g_Transfo ); // g_Transfo는 위에 있는 투영공식임.

# 픽셀 쉐이더

// UV 좌표 계산

float2 ProjectedTexCoords;
ProjectedTexCoords.x = input.ReflectPos.x / input.ReflectPos.w / 2.0f + 0.5f;
ProjectedTexCoords.y = -input.ReflectPos.y / input.ReflectPos.w / 2.0f + 0.5f;

후에 계산된 좌표값으로 샘플링 하면 된다.

참고사항 :

// 펙셀에서 저렇게 하는 이유 ( GPG 에있는 june8036님의 답변 )

x/w, y/w가 x/뷰변환된z y/뷰변환된z 라고 생각하면 될꺼 같네요.
D3DMatrixPerspectiveFovLH 이런 프로젝션 함수를 직접 구현해보시면 더 느낌이 오실거 같은데요.
결국 마지막 w값은 뷰변환되어져 나온 z값과 같이 되지요.
그래서 이 뷰변환된 z값을 x, y에 나누어 주면, 멀리 있는 물체는 화면의 정 중간에서 더 가깝게
만들어지고, 가까운 물체는 화면의 정 중간에서 더 멀게 나오는걸로 알고 있습니다.






http://blog.naver.com/doridori3510/30127128770


+ 수면 아래 장면 만들기

수면 위의 반사장면 만드는것과 동일하게 물을 기준으로 아래 장면을 텍스쳐로 만든후.

물 평면에 투영한다 !

좀더 좋은 효과를 만들기위해서 물과 지형과의 거리에 비례해서 알파값을 계산한다 !

TIP. 수면 아래 지형을 렌더링할때 픽셀 쉐이더 코드

// 수면과 지형의 거리 계산
float d = fWaterHeight - ((input.WorldPos.y) * test_Y );

// 색상공식
float4 r0;
r0.a = mul( test_A, d );
r0.a = saturate( r0.a );
r0.a = sqrt( r0.a );
r0.a = saturate( r0.a );

r0.r = saturate( exp2( -d * test_R ) );
r0.g = saturate( exp2( -d * test_G ) );
r0.b = saturate( exp2( -d * test_B ) );

+ 프레넬 공식에 비례해서 수면 위 장면, 수면 아래 장면을 섞어서 그릴지 계산.

TIP. 물 픽셀 쉐이더 코드에서 프레넬 계산

// 프레넬로 혼합
float fresnelTerm = (float)0;
fresnelTerm = 0.02+0.97f*pow((1-dot(eyeVector, normalVector)),5);
fresnelTerm = fresnelTerm * fresnelForce * DwColor.a; // 프레넬도 알파 적용
fresnelTerm = saturate( fresnelTerm );

// 프레넬로 반사,굴절 색상 결정
float4 mixColor = ( UpColor * fresnelTerm ) + ( DwColor * (1-fresnelTerm) );

+ 범프 텍스쳐를 기준으로, 수면 위, 아래 장면의 UV를 흔든다.

TIP. 물 픽셀 쉐이더 코드에서 범프 UV계산

// 범프 계산
float4 bumpColor1 = tex2D( bump_sampler, input.BumpPos1 );
float4 bumpColor2 = tex2D( bump_sampler, input.BumpPos2 );
float4 bumpColor = (bumpColor1 * fBumpRate ) + ( bumpColor2 * (1-fBumpRate) );

// 수면 아래
float2 DwBump = fDwBumpForce * (bumpColor.rg - 0.5f);
float4 DwPos = input.DwPos;
DwPos.xy += DwBump;
float4 DwColor = tex2Dproj( Dw_sampler, DwPos );

// 수면위
float2 UpBump = fUpBumpForce * (bumpColor.rg - 0.5f);
float4 UpPos = input.UpPos;
UpPos.xy += UpBump;
float4 UpColor = tex2Dproj( Up_sampler, UpPos );

+ 범프 텍스쳐를 노멀벡터로 생각해서 각각의 조명을 계산한다.

범프 텍스쳐를 기준으로 노멀 벡터를 구하는데, 노멀벡터의 Y값을 세우기 위해서 Z값을 Y값으로 생각해서 채워 넣는다.

이 방법이 통하는것은.

물이 평면이고 접선공간으로 변환해서 하는 결과값 ( bump.rgb * 조명방향[접선공간] ) = (bump.rbg)

이 성립하기 때문이다.

정확하게 말하자면, bump에서 읽어온 노멀값과 접선공간으로 변환된 조명과 연산해야한다.

// 조명의 방향을 접선공간으로 변형.
o.LightDir.x = dot(worldLightDirection, T);
o.LightDir.y = dot(worldLightDirection, B);
o.LightDir.z = dot(worldLightDirection, N);

// ViewVec 역시 접선공간으로 변형.

float3 viewVec = normalize(vWorldCameraPos - worldPos);
o.ViewVec.x = dot(viewVec, T);
o.ViewVec.y = dot(viewVec, B);
o.ViewVec.z = dot(viewVec, N);

ㅇㅇㅁㅅㅄ
TIP. 물 픽셀 쉐이더에서 조명 계산

// 범프에 따른 노멀벡터 구하기
float4 nomalBump = bumpColor * 2.0f - 1.0f; // 텍스쳐 좌표값을 노멀맵으로 변환
float4 bumpNormalVector = float4( nomalBump.r, nomalBump.b, nomalBump.g, nomalBump.a );
float4 normalVector = normalize( bumpNormalVector );

// 조명 계산
float4 Color = CalcAmbient() + CalcDiffuse( normalVector );

// 스펙큘라
float4 half = normalize( -LightDirection + eyeVector );
float4 speccolor = CalcSpecular( normalVector * fNomalPower, half, fSpecPower );

+ 최종적인 물의 칼라값 결정

원래 물 고유의 색상과 혼합한다.

TIP. 물 픽셀 쉐이더의 최종 output 색상

// 물 색상
float4 waterColor = float4(water_R, water_G, water_B, water_A );

float4 outputColor = ( ( (waterColor * rate) + ( mixColor * (1 - rate ) ) ) * Color ) + speccolor;
outputColor.a = DwColor.a; // 물깊이에 따른 알파값 적용

< 최종적인 스샷 >

세부적인 수치같은거 조절해야하는데... 귀찮다 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

암튼 색상이랑 수치 비율이랑 조절하면 더 예뻐질것임. 성형수술같네;ㅁ;

비행기는 계속해서 움직이고 수면에 실시간으로 반사함 !

< 수치 조절 좀 했더니 >엉? 사진올려놓고 보니 비슷비슷한가?ㅋㅋ 실제로 보면 아닌데 ㅜ.ㅜ

[출처] water shader ! 물효과!|작성자 달혜

반응형
반응형

반응형
반응형

  • #1 written by djmj
    about 7 months ago

    You are looking up 10 and not 9 pixels! Coordinate 0.0 intersects two pixels and so you take full advantage of linear interpolation! Else you need to offset by half a pixel!

    Where is the benefit of the usual easier way? Lookup at coordinates [-4, -2, 0, 2, 4] to get 10 pixel range and then apply the weighting of each two texels and calculate final value?

  • #2 written by Andrew Moffat
    about 6 months ago

    Hi Daniel,

    This article was incredibly clear and informative. Thank you for taking the time to put it together. I’m still learning this stuff, so this was very helpful.

    I wrote up a small Python script based on this post to generate the gaussian texture lookups, optimized for linear sampling. Maybe it can be useful to someone else too:

    https://gist.github.com/2332010

    Thanks again

  • #3 written by Oskar Elek
    about 1 month ago

    Hey Daniel,

    nice article, the connection with Pascal’s triangle is indeed very interesting.

    I would like to add two things. First, maybe it would be good to add that Gaussian has a unit integral, since it’s probably one of the reasons the filtering works (in the continuous case at least). The 3D plot should also reflect this (meaning that such a wide Gaussian certainly wouldn’t reach a value of 1.6). This is of course just minor.

    The second thing that struck me was:
    “A Gaussian function with a distribution of 2σ is equivalent with the product of two Gaussian functions with a distribution of σ.”
    This is just my opinion, but I think this doesn’t hold. First, I think such product won’t be a 2σ-Gaussian (properly normalized and all). Second, a repeated application of any filter corresponds to applying their *convolution*, which differs from product. And, convolution of two Gaussians with StD=σ produces a Gaussian with StD=Sqrt(2*σ^2)=σ*Sqrt(2).

    I think what you meant was that product of 2 polynoms with order n (n-th row of Pascal triangle) gives you a polynom of order 2n? That should be true.

    What do you think?
    Oskar

  • #4 written by Christian Cann Schuldt Jensen
    about 1 month ago

    You can do a 9-tap gaussian using only 2 texture fetches by sampling at one of corner of the center pixel in the first pass (f.x with an xy-offset of -0.5,0.5 ) and then sample the opposite corner in the next pass ( xy-offset of 0.5,-0.5 )

    This results in the standard
    121
    242
    121
    9-tap gaussian.

    You can do the same gaussian in a single pass if you sample at all 4 corners (4 texture fetches)

    You can do a nice and very fast 7-tap blur in a single pass if you sample two opposite corners with an offset of 1/3 away from the center.

    This results in a
    121
    282
    121
    convolution kernel.
    If you calculate the strength of the blur by subtracting from the center pixel you can then scale the result so that it closely matches the regular 9-tap gaussian.

    I also do a 17-tap blur using only 5 fetches in a single pass by sampling the center pixel and then offsets (0.4,-1.2) , (-1.2,-0.4) , (1.2,0.4) and (-0.4,1.2).
    I then adjust the strength of it to more closely match the 9-tap gaussian.

반응형
반응형

구글링하다 찾은 펄린노이즈

알려진 펄린노이즈의 방법은 전체적인 대강의 윤곽은 비슷 할 수 있찌만 내부적으로 세세히 조금씩 다른

방법들이 있는데 아래 필자가 쓴 방법이 좀더 빠른 연산을 보인다고 한다

tip : 일부 내적에 대한 부족한 설명을 '편집' 이라는 부분에 보충 설명을 해놓음

1차로 예를 들면..

펄린노이즈는 각 정수 단위 사이에들어오는 성분(x) 에 대해서 -1 ~1 사이의 난수 값을 생성해 낸다

각 구간마다 난수벡터를 만들어 놓고 성분(x) x 가 어느 정수 구간 1 거리 사이안에 들어 간다면

ex( 244 ~255) 이 구간 244 와 255 에 설정되어 있는 난수값과 244 와 255 에서 x 값을 향하는 벡터와의 각 내적 값들을

3차 방정식이 x 축이 되는 x ----- > 3차 --------> 선형 보간----------- > v0 ~ v1 의 값으로 보간 되는

즉 일반적으로 선형 보간 된 값이 v0 또는 v1 쪽으로 더 쏠리는 보간값의 형태가 되어

최종 결과 값은 v0 와 v1 의 중간 값보다는 v0 쪽이나 v1 쪽에 더 영향을 받는 난수 값을 얻게 된다

2차는 1차 사이의 보간을 통해

3차는 2차 사이의 보간을 통해 구한다


http://webstaff.itn.liu.se/~stegu/TNM022-2005/perlinnoiselinks/perlin-noise-math-faq.html#toc-algorithm

The Perlin noise math FAQ

by Matt Zucker

v. 1.0, last updated February 2001


Table of Contents


About this document

So far, I have found two really great sources for information about Perlin noise. They are Ken Perlin's Making Noise web site, which has a comprehensive introduction to the topic, and Hugo Elias's page, which features some algorithms and a few more detailed examples of applications. This document is intended to complement those two valuable resources by explaining in more depth, hopefully in plain English, some of the math involved in Ken Perlin's original implementation of Perlin noise.

I wrote a demo program in C++ that includes a Perlin noise texture class, which I hope provides a decent example of C++ code for Perlin noise. You can find the demo at http://www.robo-murito.net/code.html.

If I've made any grave errors or you just want to comment, feel free to email me.


What is Perlin noise?

Perlin noise is function for generating coherent noise over a space. Coherent noise means that for any two points in the space, the value of the noise function changes smoothly as you move from one point to the other -- that is, there are no discontinuities.


Non-coherent noise (left) and Perlin noise (right)

When I talk about a noise function, I mean a function that takes a coordinate in some space and maps it to a real number between -1 and 1. Note that you can make noise functions for any arbitrary dimension. The noise functions above are 2-dimensional, but you can graph a 1-dimensional noise function just like you would graph any old function of one variable, or consider noise functions returning a real number for every point in a 3D space.

These images were all created using nothing but Perlin noise:

Besides these trivial images, there are countless interesting applications for noise in computer graphics. Look at Hugo Elias' page or Ken Perlin's pages for some pretty examples, in-depth explanations and nifty ideas.


How do you generate Perlin noise?

I've seen implementations on the internet that take non-coherent noise, as shown above, and smooth it (with something like a blur function) so it becomes coherent noise, but that can end up being more computationally expensive than the function I'll present here, which is more or less theoriginal implementation that Ken Perlin came up with. The problem with Perlin's implementation on its own was that that reading the descriptions of the math published on Perlin's website was a bit like reading Greek -- it took me about a week of reading his code and notes to figure out the actual geometric interpretations of the math. So hopefully this document can trim down that learning curve.

Let's look at the 2D case, where we have the function

noise2d(x, y) = z,

with x, y, and z all real (floating-point) numbers. We'll define the noise function on a regular grid, where grid points are defined for each whole number, and any number with a fractional part (i.e. 3.14) lies between grid points. Consider finding the value of noise2d(x, y), with x and y both notwhole numbers -- that is, the point (x, y) lies somewhere in the middle of a square in our grid. The first thing we do is look at the gridpointssurrounding (x, y). In the 2D plane, we have 4 of them, which we will call (x0, y0), (x0, y1), (x1, y0), and (x1, y1).


The 4 grid points bounding (x, y)

Now we need a function

g(xgrid, ygrid) = (gx, gy)

which takes each grid point and assigns it a pseudorandom gradient of length 1 in R2 ('gradient' is just the name for an ordered pair or vector that we think of as pointing in a particular direction). By pseudorandom, we mean that g has the appearance of randomness, but with the important consideration that it always returns the same gradient for the same grid point, every time it's calculated. It's also important that every direction hasan equal chance of being picked.


The 4 pseudorandom gradients associated with the grid points

Also, for each grid point, we generate a vector going from the grid point to (x, y), which is easily calculated by subtracting the grid point from (x, y).


Vectors from the grid points to (x, y)

Now we have enough to start calculating the value of the noise function at (x, y). What we'll do is calculate the influence of each pseudorandom gradient on the final output, and generate our output as a weighted average of those influences.

First of all, the influence of each gradient can be calculated by performing a dot product of the gradient and the vector going from its associated grid point to (x, y). A refresher on the dot product -- remember, it's just the sum of the products of all the components of two vectors, as in

(a, b) · (c, d) = ac + bd .

Since I'm really tired of writing subscripts, we'll just refer to these 4 values as s, t, u, and v, where

s = g(x0, y0) · ((x, y) - (x0, y0)) ,
t = g(x1, y0) · ((x, y) - (x1, y0)) ,
u = g(x0, y1) · ((x, y) - (x0, y1)) ,
v = g(x1, y1) · ((x, y) - (x1, y1)) .

So here's a 3D-ish picture of some influences s, t, u, and v coming out of the R2 plane (note that these probably wouldn't be the actual values generated by the dot products of the vectors pictured above).


Influences from the grid points

Geometrically, the dot product is proportional to the cosine of the angle between two vectors

, though its unclear to me

------------------------------------------------------------------------------------------

편집 : 다른 곳에서 보니....

내적이 의미 하는게 사각 셀(사각형 안의 x,y 에 해당하는) 것의 4 귀퉁위의 각 높이값을

말하는 듯..

------------------------------------------------------------------------------------------

if that geometrical interpretation helps one visualize what's going on. The important thing to know at this point is that we have four numbers, s, t, u, and v which are uniquely determined by (x, y) and the pseudorandom gradient function g. Now we need a way to combine them to get noise2d(x, y), and as I suggested before, some sort of average will do the trick.

I'm going to state the obvious here and say that if we want to take an average of four numbers, what we can actually do is this:

  1. find the average of the first pair of numbers
  2. find the average of the second pair of numbers
  3. average those two new numbers together

-- and that's the strategy we'll take here. We'll average the "front" values s and t first, then average the "rear" values u and v. This works to our advantage because the points below s and t, and similarly below u and v vary only in the x dimension -- so we only have to worry about dealing with one dimension at a time.

We're not taking a plain vanilla-flavored average here, but instead, a weighted average. That is, the value of the noise function should be influenced more by s than t when x is closer to x0 than x1 (as is the case in the pictures above). In fact, it ends up being nice to arrange things so that x and y values behave as if they are slightly closer to one grid point or the other than they actually are because that has a smoothing effect on the final output. I know that sounds really silly, but noise without this property looks really stupid. In fact, it sounds so silly that I'm going to write it again: we're going to want the input point to behave as if its closer to one grid point or another than it actually is.

This is where we introduce the concept of the ease curve. The function 3p² - 2p³ generates a nice S-shaped curve that has a few characteristics that are good for our purposes.


Meet the ease curve

What the ease curve does is to exaggerate the proximity its input to zero or one. For inputs that are sort of close to zero, it outputs a numberreally close to zero. For inputs close to one, it outputs a number really close to one. And when the input is exactly one half, it outputs exactly one half. Also, it's symmetrical in the sense that it exaggerates to the same degree on both sides of p = ½. So if we can treat one grid point as the zero value, and the other as the one value, the ease curve has the exact smoothing effect that just we said we wanted.

Ok, I've droned on long enough, it's calculation time: first, we take the value of the ease curve at x - x0 to get a weight Sx. Then we can find the weighted average of s and t by constructing a linear function that maps 0 to s and 1 to t, and evaluating it at our x dimension weight Sx. We'll call this average a. We'll do the same for u and v, and call the result b.


Finding the first two averages using linear interpolation

The above figures should satisfy you that no matter where x happens to fall in the grid, the final averages will always be between s and t, and u andv, respectively. Mathematically, this is all simple to calculate:

Sx = 3(x - x0)² - 2(x - x0
a = s + Sx(t - s)
b = u + Sx(v - u)

Now we find our y dimension weight, Sy, by evaluating the ease curve at y - y0, and finally we take a weighted sum of a and b to get our final output value z.


A weighted sum of the first two averages yields the final output

And there you have it. So all you have to do is call the noise function for every pixel you want to color, and you're done. Probably.

...and they all lived happpily ever after.

The End.

An interesting consequence of all of this is that the noise function becomes zero when x and y are both whole numbers. This is because the vector (x, y) - (x0, y0) will be the zero vector. Then the dot product of that vector and g(x0, y0)will evaluate to zero, and the weights for the averages will also always be zero, so that the zero dot product will influence the final answer 100%. The funny thing is that looking at the noise function, you would never guess that it ends up being zero at regular intervals.


Computational complexity

If you want to extend the noise function to n dimensions, you'll need to consider 2n grid points, and perform 2(n - 1) weighted sums. The implementation presented here has a computational complexity of O(2(n - 1)), which means that you'll really start to drag if you want to look at 5-, 6-, or greater dimensional noises.


Speeding it up

We could increase the speed of the noise function if we didn't have to compute the pseudorandom gradient every time we called the noise function (because for every x between some x0 and x1 and y between some y0 and y1, we have to recalculate the same four gradients every time the noise function is called!) The nice thing to do would be to precalculate the gradient for every possible (xgrid, ygrid), but xgrid and ygrid are allowed to vary all over the real plane! How could we possible precalculate every value?

The neat thing about noise is that it's locally variable, but globally flat -- so if we zoom out to a large degree, it will just look like a uniform value (zero in fact). So, we don't care if the noise function starts to repeat after large intervals, because once you're zoomed out far enough to see the repeat, it all looks totally flat anyways.

So now we should feel justified in doing a little trick with modulus. Say we're doing noise in 3D, and we want to find the gradient for some grid point (i, j, k). Let's precompute a permutation table P, that maps every integer from 0 to 255 to another integer in the same range (possibly even the same number). Also, let's precompute a table of 256 pseudorandom gradients and put it in G, so that G[n] is some 3-element gradient.

Now,

g(i, j, k) = G[ ( i + P[ (j + P[k]) mod 256 ] ) mod 256 ]

But on a computer, modulus with 256 is the same thing as a bitwise and with 255, which is a very fast operation to perform. Now we've reduced the problem of a possibly involved function call into nothing but some table lookups and bitwise operations. Granted, the gradients repeat every 256 units in each dimenstion, but as demonstrated, it doesn't matter.

This speedup is also mentioned on Perlin's web page, and is actually used in his original implementation.


Looping noise

What if you want to use procedural noise to calculate a repeating animation of a licking flame or rolling clouds? It is true that noise on it's own doesn't tend to repeat discernably, and that's great for generating ever-changing images; however, if you want to prerender an animation, you'll probably want it to repeat. Given that F is your function that generates a real number from a point in noise-space, and you want your animation to repeat every t units, you define a new function that loops when z is between 0 and t:

Floop(x, y, z) = ( (t - z) * F(x, y, z) + (z) * F(x, y, z - t) ) / (t)

Now each function call takes twice as long to calculate, but since you're probably not going to use this cycling technique in real time, it probably doesn't matter.

The explanation

Consider the graph of a noise function F(x, y, z) for some fixed x and y. The problem is, you want F(0) = F(t) and there is no guarantee that will be the case with any old x, y, and t. Actually, since any given x and y should have no influence on the repeating aspect of the animation, we can for all practical purposes throw them out while we're developing our repeating function, and consider the simplified case of a one-dimensional noise function F(z).


A one-dimensional noise function

We need to take this function and change it into one where it is guaranteed that F(0) = F(t). Here's an expanded view of our noise function showing its behavior from -t to t:


The same, function, ranging over a positive and negative domain

Now we define a new function F'(z) that behaves like F(z) when z is near zero, but behaves like F(z - t) when z is near t. If you think about it, you see that F'(0) = F(0), and that F'(t) = F(t - t) = F(0). We can do this with a simple linear interpolation by considering a linear function which is equal to F(z) at 0, and equal to F(z - t) at t.

High school algebra tells us that this linear function has a slope of

(rise) / (run) = (F(z - t) - F(z)) / (t - 0) = (F(z - t) - F(z)) / t

and an intercept of F(z). Now we set up F' as this linear interpolation operating on z:

F'(z) = slope(z) + intercept
= ( (F(z - t) - F(z)) / t )(z) + F(z)
= ( ( (z) * F(z - t) - (z) * F(z) ) / t ) + F(z)
= ( ( (z) * F(z - t) - (z) * F(z) ) / t ) + (t / t) * F(z)
= ( (z) * F(z - t) - (z) * F(z) + (t) * F(z)) / (t)
= ( (z) * F(z - t) + (t-z) * F(z) ) / (t)
= ( (t-z) * F(z) + (z) * F(z - t) ) / (t)

Which is basically the same as the function given above. If you look at F' next to F, you can see that the function does indeed repeat in that F'(0) = F'(t). Also notice that the peaks just to the right of F'(0) are the same as the peaks just to the right of F'(0), and that the peaks just to the left ofF'(t) are virtually identical to the peaks just to the left of F(0).


The old function (left), and the new, repeating function (right)

If you had a little calculus and too much free time, you could prove that this looping (and the tiling in the next section) is truly seamless: not only does F(0) = F'(t), but all their derivatives should match up as well. Which means that no one should be able to tell where the repeat actually happens.


Seamlessly tiling noise

Say you're using a noise function to generate textures for a polygon-based engine. Chances are, you might want the textures to be tileable. You can extend the above example to generate tileable 2-dimensional noise that repeats every w units in the x dimension and every h units in the y dimension. This will require a weighted sum of four calls to the original function (which again, for lack of imagination, we will call F).

Ftileable(x, y) = (
F(x, y) * (w - x) * (h - y) +
F(x - w, y) * (x) * (h - y) +
F(x - w, y - h) * (x) * (y) +
F(x, y - h) * (w - x) * (y)
) / (wh)

A pattern should be emerging here, so it shouldn't surprise you that you'll need evaluate a weighted sum of 8 calls to the noise function if you want to have a repeating animation that tiles in the x and y dimenstions. I'm not going to write it out here out of space considerations, and also because it should be evident what the sum will be.

반응형
반응형



http://www.math.union.edu/~dpvc/talks/2001-04-28.HRUMC/vertices-2.html

Hypercube Vertices


1 2 4 8 16
0D 1D 2D 3D 4D

The hypercube has 16 = 24 vertices



반응형
반응형

http://apophysis.org/


Apophysis

Freeware fractal flame editor for Windows

artifact.jpg (7690 bytes) earles.jpg (11193 bytes)

Apophysis Forum

Apophysis at SourceForge





http://www.ultrafractal.com/download/index.php




Ultra Fractal 5

Download your copy of Ultra Fractal 5 here:

Windows
Version 5.04 — Windows 7, Vista and XP

After installing, Ultra Fractal will run as a free trial version for 30 days. If you already have purchased a license key, simply enter it when Ultra Fractal starts to unlock full functionality.

Installation (Windows)

After downloading, double-click on the downloaded file to install Ultra Fractal. When you first start Ultra Fractal, a welcome screen will appear that provides access to tutorials and online help to help you to get started quickly.

Evaluation

The downloaded evaluation version is fully functional, except that exported and rendered images are marked as written by an evaluation copy. If you have a license for Ultra Fractal 5, enter it when starting the program to turn the trial version into a full version.

If you want to keep using Ultra Fractal after the 30-day trial period, you must purchase a copy in the Ultra Fractal shop. You can also purchase a site license if you need more than one copy.

Ultra Fractal 5.04

Released August 11, 2010, version 5.04 contains bug fixes and improvements.

Release notes

The included help file is also available in PDF format for easy printing.

Download PDF manual

All rights reserved. Copyright © 1997-2012 Frederik Slijkerman

반응형
반응형


반응형
반응형

GPG 에 기술된 펄린노이즈

http://www.gpgstudy.com/gpgiki/PerlinNoise


원문

http://freespace.virgin.net/hugo.elias/models/m_perlin.htm


http://www.redwiki.net/wiki/wiki.php/Perlin%20Noise

* 원문링크 : [http]http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
  • 원문 번역링크 : GpGiki:PerlinNoise
  • 이 글은 제가 번역한 것이 아님을 밝힙니다. GpGiki에서 여러 전문가분들이 번역을 해주신 건데, 원문과 번역이 섞여있어 읽기 힘든 까닭에 제가 다시 정리하기 위해 이리로 복사해 온 것입니다. 원문을 읽어보시려면 위의 원문번역링크를 참조하시길...

Contents

[-]
1 시작하며
2 노이즈 함수의 소개
3 정의
4 펄린 노이즈 함수 만들기
5 Persistence (지속성)
6 옥타브
7 당신만의 노이즈 함수 만들기
8 보간
8.1 선형 보간
8.2 코사인 보간
8.3 3차 보간
9 매끈한 노이즈
10 모두 합치기
10.1 1차원 펄린 노이즈 Pseudo 코드
10.2 2차원 펄린 노이즈 Pseudo 코드
11 펄린 노이즈의 응용분야
11.1 1 차원
11.2 2 차원
11.3 3 차원
11.4 4 차원
12 Perlin Noise 를 이용한 텍스쳐 생성
13 참고문헌 및 링크

1 시작하며

많은 사람들이 프로그램에서 불예측성을 만들어내고 물체의 동작과 행동이 좀더 자연스럽게 보이게 하거나 또는 텍스쳐를 생성해 내기 위해 난수생성기를 사용해 왔다. 난수생성기는 확실히 나름대로의 쓸모가 있지만, 종종 출력값들이 너무 조악해서 자연스러워 보이지 않을때가 있다. 이글에서는 매우 다양한 용도로 사용할 수 있는 함수 하나를 소개하겠다. 기본적으로 이 함수는 자연스럽게 보이는 뭔가가 필요한 경우라면 언제라도 사용할 수 있다. 이 글에서 필자가 제시하는 용도 이외의 용도들도 얼마든지 찾을 수 있을 것이다.

자연에 있는 많은 것들을 보게 되면, 그것들이 프랙탈이라는 것을 알게 될 것이다. 그것들은 다양한 수준의 정밀함(detail)을 가지고 있다. 산맥의 외곽선을 보게되면, 높이의 변화가 큰 것(산), 중간인 것(언덕), 작은 것(구릉), 조그마한 것(돌맹이), 그외에도 계속 나열할 수 있는 변화들이 있다. 더불어 들판에 누덕누덕 자라난 풀들의 분포, 바다의 파도, 개미의 이동, 나무가지의 뻗침, 구슬의 무늬, 바람같은 대부분의 삼라만상의 현상을 보면, 모두 크고 작은 차이지만 똑같은 경향을 보여준다. 펄린 노이즈 함수는 노이즈 함수를 다양한 비율의 범위로 더함으로써 간단히 이런 현상을 재창조한다.

펄린 노이즈 함수를 만들기 위해서는 노이즈 함수와 보간함수 두가지가 필요하다.

2 노이즈 함수의 소개

노이즈 함수는 본질적으로 seed 값에 의한 난수생성기이다. 인자로 하나의 정수를 받아서 그 인자에 기반한 난수를 반환한다. 만약 똑같은 인자를 두 번 전달하면 동일한 수가 두 번 생성된다. 이런 식으로 동작한다는 건 매우 중요한 사실이다. 그렇지 않다면 펄린 함수는 쓸모없는 것을 생성할 것이다.


여기 노이즈 함수의 예를 나타내는 그래프가 있다. 0 에서 1 사이의 난수가 X 축의 모든 점에 배정되었다.


이 값들 사이를 부드럽게 보간함으로써 전달인자를 정수로 받지 않는 연속적인 함수를 정의할수 있게 된다. 이 글의 뒤에서 이 값들을 보간하는 다양한 방법에 대해 논해보겠다.

3 정의

더 얘기하기 전에 진폭(amplitude)과 주파수(frequency)에 대해 내가 의도하려는 걸 정의해 보겠다. 만약 당신이 물리를 공부해왔다면 사인파에 적용된 진폭과 주파수의 개념이 떠오르는게 당연하다.


  • sin 곡선 : sin 곡선의 파장은 한 꼭대기로부터 다른 꼭대기까지의 거리다. 진폭은 sin곡선의 높이다. 주파수는 1/wavelength 로 정의된다.

http://freespace.virgin.net/hugo.elias/models/m_ranwav.gif

  • 노이즈 곡선 : 이 노이즈 함수의 예제 그래프에서 빨간 점은 함수의 차원에 따라 정의된 난수값을 가리킨다. 이 경우에 진폭은 함수가 가질 수 있는 최대, 최소값의 차이가 된다. 파장은 한 빨간 점으로부터 다음 점까지의 거리이다. 역시 주파수는 1/wavelength 로 정의된다.

4 펄린 노이즈 함수 만들기

이제, 다양한 주파수와 진폭을 가진 부드러운 함수들을 많이 가지고 있다면, 그 함수들을 모두 더함으로써 멋진 노이즈 함수를 만들 수 있다. 이것이 펄린 노이즈 함수다.

다음 노이즈 함수들을


모두 더해보자. 이런 것이 얻어진다.


이 함수가 큰, 중간정도의, 그리고 작은 변화들을 가지고 있다는 걸 볼수 있다. 당신은 이게 산맥하고 상당히 비슷하게 보인다고 생각할지도 모른다. 실제로 많은 컴퓨터가 생성한 지형은 이 방법으로 만들어진 것이다. 물론 그것들은 2차원 노이즈를 사용하고, 여기에 대해서는 잠시 후에 다루기로 하겠다.

물론 당신은 2차원에서도 똑같이 할수 있다. 몇몇 노이즈 함수는 2차원에서 생성된다.


이 함수를 모두 더하면 하나의 노이즈 형태가 생성된다.


5 Persistence (지속성)

이 노이즈 함수들을 모두 더할때 각각의 함수가 정확히 어떤 진폭과 주파수를 사용하는지 궁금할 것이다. 위의 일차원 예제는 각각 연속적으로 더해지는 노이즈 함수에 대해 주파수는 두배로, 진폭은 반으로 해서 사용했다. 이것은 매우 잘 알려진 방법이다. 사실 사람들이 다른 걸 사용하려고 생각해 보지도 않을 정도로 너무 잘 알려져있다. 그러나 각 단계마다 다른 주파수와 진폭을 사용함으로써 다양한 특징의 펄린 노이즈 함수를 만들어낼 수 있다. 예를 들어 부드럽게 기복하는 언덕을 만들기 위해 큰 진폭과 낮은 주파수를 사용하거나 매우 작은 진폭에 높은 주파수를 사용할 수 있다. 또는 작은 진폭에 낮은 주파수를 선택해서 평평하지만 바위투성이인 평원을 만들 수도 있다.

좀 더 간단하면서 진폭과 주파수라는 말이 항상 반복되는걸 피하기 위해 하나의 숫자가 각 주파수의 진폭을 지정하는데 쓰인다. 이 값은 Persistence 로 알려져 있다. 이것의 정확한 의미에는 약간 모호성이 있다. 그 용어는 원래 프랙탈의 발견뒤에 있는 사람중 한명인 Mandelbrot 에 의해서 만들어졌다. 그는 높은 주파수를 많이 가지고 있는 노이즈를 persistence 가 낮다고 정의했다. 내 친구인 Matt 또한 persistence 의 개념을 보충했지만 다른 방법으로 정의했다. Mandelbrot 씨께 미안하지만, 솔직히 나는 Matt 의 정의를 선호한다. 그래서 우리의 persistence 의 정의는 다음과 같다.

frequency = 2^i
amplitude = persistence^i

i 는 추가되는 i 번째 노이즈 함수를 가리킨다. 펄린노이즈의 출력에 persistence 의 효과를 설명하기 위해 아래의 도표를 한번 보자. 이것들은 더해지는 노이즈 함수의 구성요소, persistence 값의 효과, 펄린 노이즈 함수의 결과를 보여준다.

Frequency 1 2 4 8 16 32


Amplitude: 1 1/4 1/16 1/64 1/256 1/1024 result


Amplitude: 1 1/2 1/4 1/8 1/16 1/32 result


Amplitude: 1 1/1.414 1/2 1/2.828 1/4 1/5.656 result


Amplitude: 1 1 1 1 1 1 result

6 옥타브

각각의 더해지는 연속적인 노이즈 함수를 옥타브라고 부른다. 이렇게 불리는 이유는 각각의 노이즈 함수가 이전의 것보다 두배의 주파수를 갖기 때문이다. 음악에서의 옥타브도 이런 성질을 갖는다.

정확히 얼마나 많은 옥타브를 더할것인가는 전적으로 당신에게 달렸다. 가능한한 많이 더할수도 있고 원하는 만큼 약간만 더할수도 있다. 그러나 약간의 제안을 하겠다. 만약 당신이 펄린 노이즈 함수를 화면에 이미지를 만드는데 사용중이라면 옥타브가 너무 높은 주파수를 가져서 화면에 표시할수 없을때가 올것이다. 매우 높은 주파수의 노이즈 함수의 작은 디테일을 모두 복사하기에는 화면의 픽셀이 충분하게 있지 않을 것이다. 펄린 노이즈의 몇몇 구현은 화면(또는 다른 매체)의 한계에 도달할때까지 가능한 만큼의 노이즈 함수를 자동적으로 더한다.

진폭이 너무 작아서 복사하지 못하게 될때 노이즈 함수를 더하는걸 중지하는게 현명하다. 정확히 언제 이런일이 일어나는지는 persistence 의 정도, 펄린 함수의 전체적인 진폭 그리고 화면(또는 뭐든지)의 해상도에 달렸다.

7 당신만의 노이즈 함수 만들기

우리는 노이즈 함수로 무엇을 할것인가? 기본적으로는 난수생성기로 사용한다. 하지만 다른 난수발생기에서 프로그램에서 호출할 때마다 매번 다른 난수를 만들어 내는 것과는 다르게, 노이즈 함수에서는 하나 또는 그 이상의 매개변수를 계산하여 난수를 발생시킨다. 예를 들어 똑같은 수를 노이즈 함수에 넘기면 함수는 매번 똑같은 수를 만들어 낼 것이지만, 다른 수를 넘겨주면 함수는 다른 수를 만들어 낼 것이다.

글쎄, 나는 난수생성기에 대해 많은걸 알지 못해서 뭔가 찾으러 다녔고, 여기 내가 발견한게 하나 있다. 이건 매우 좋아보인다. -1.0 과 1.0 사이의 부동소수를 돌려준다.

  function IntNoise(32-bit integer: x)

    x = (x<<13) ^ x;
    return ( 1.0 - ( (x * (x * x * 15731 + 789221) + 1376312589) & 7fffffff) / 1073741824.0);

  end IntNoise function

이제 당신은 몇가지 난수생성기가 필요할 것이므로, 나는 위의 코드의 몇가지 복사본을 만들기로 제안한다. 하지만 약간만 다른 숫자를 사용한다. 저기 엄청나게 무서워 보이는 숫자들은 모두 소수들이다. 따라서 당신은 비슷한 크기의 몇개의 다른 소수를 사용할 수 있다. 당신이 난수를 찾는걸 돕기 위해 나는 소수를 나열하는 작은 프로그램을 만들었다. 시작할 숫자와 끝날 숫자를 넘겨주면 이 프로그램은 그 사이에 있는 모든 소수를 찾는다. 소스코드도 포함되어 있으니 무작위 소수를 생성하기 위해 당신은 자신의 프로그램에 쉽게 포함시킬수 있다. [http]Primes.zip

8 보간

노이즈 함수를 만들면서 당신은 리턴값이 부드럽게 나오는것이 필요할 것이다. 또한번 당신이 좋아하는 어떤 방법이고 취할수 있지만, 어떤 방법은 다른 방법보다 더 나아 보인다. 표준보간함수는 이 값들 사이를 보간할 a, b 값과 0 과 1 사이의 값을 받을 x 값, 이렇게 3개의 입력을 받는다. 보간함수는 x 에 기반하여 a 와 b 사이의 값을 돌려준다. x 가 0이면은 a 를 돌려주고 x 가 1이면은 b 를 돌려준다. x 가 0과 1사이면 a 와 b사이의 어떤 값을 돌려준다.

8.1 선형 보간

이처럼 간단한 '플라즈마'같은 형편없어 보이는 방법을 모든 이들이 지형생성을 위해 사용한다.(Looks awful, like those cheap 'plasmas' that everyone uses to generate landscapes.) 비록 간단한 알고리즘이지만 펄린 노이즈를 실시간으로 사용할 거라면 용납될것 같다.

  function Linear_Interpolate(a, b, x)
	return  a*(1-x) + b*x
  end of function


8.2 코사인 보간

이 방법은 선형 보간보다 훨씬 부드러운 커브를 제공한다. 만약 속도 상의 약간의 손실을 감수할 수 있다면, 이 방법이 명백히 더 낫고 노력할만한 가치가 있다.

  function Cosine_Interpolate(a, b, x)
	ft = x * 3.1415927
	f = (1 - cos(ft)) * .5

	return  a*(1-f) + b*f
  end of function


8.3 3차 보간

이 방법은 매우 부드러운 결과를 제공하지만, 속도의 저하를 감수해야 한다. 솔직히 말하자면, 나는 이 방법이 코사인 보간보다 현저하게 더 나은 결과를 제공한다고는 확신할 수 없지만, 어쨋든 원한다면 사용하라. 다소 복잡하기 때문에 주의깊게 살펴보아야 한다. 이전의 보간함수가 세개의 입력을 취하는데 비해 3차 보간은 다섯개를 취한다. 이전것이 단지 a 와 b 만을 사용하는 대신에, 이제는 x 와 함께 v0, v1, v2 와 v3 가 필요하다. 이것이 3차보간이다:

http://freespace.virgin.net/hugo.elias/models/m_inter4b.gif
v0 = the point before a
v1 = the point a
v2 = the point b
v3 = the point after b
  function Cubic_Interpolate(v0, v1, v2, v3,x)
	P = (v3 - v2) - (v0 - v1)
	Q = (v0 - v1) - P
	R = v2 - v0
	S = v1

	return Px3 + Qx2 + Rx + S
  end of function


9 매끈한 노이즈

보간과는 다른 이야기지만, 노이즈 함수의 출력이 덜 랜덤하게 보이고 2D 나 3D 버전에서는 좀 덜 각지게(less square) 하기 위해 출력값을 부드럽게 조정할 수도 있다. smoothing 작업은 당신이 예측한 것과 많이 유사하고 이미지 smoothing 필터나 Fire 알고리즘을 만들어 본 적이 있는 사람이면 누구나 이미 이 작업에 정통하다. (Smoothing is done much as you would expect, and anyone who has written an image smoothing filter, or fire algorithm should already be familiar with the process.)

단순히 한 좌표에서의 노이즈 함수값을 얻는것보다는 그 값과 이웃값과의 평균을 얻을수도 있다. 이것이 이해가 잘 안된다면, 아래의 가상(psudo)코드를 한번 보라.

smooth 된 노이즈와 똑같은 노이즈 함수에 smoothing 되지 않은 것과의 차이를 설명한 작은 그림을 오른쪽에서 볼수 있다. smooth 노이즈가 좀더 평평하며, 절대 smooth 처리되지 않은 노이즈의 극값에 도달하지 못하고, 주파수는 대충 반정도를 보인다는걸 알수 있다. 이게 유일한 효과이기 때문에 1차원 노이즈는 거의 smoothing할 만한 점이 없다. smoothing 은 노이즈의 각짐을 줄이는 효과를 볼 수 있는 2차원이나 3차원에서 더 유용하게 된다. 불행히도 약간 대비를 감소시키기도 한다. 더 smooth 하게 만들수록, 명백히, 노이즈는 더 평평해 질 것이다.



1차원 Smooth 노이즈

  function Noise(x)
    .
    .
  end function

  function SmoothNoise_1D(x)

    return Noise(x)/2  +  Noise(x-1)/4  +  Noise(x+1)/4

  end function

2 차원 Smooth 노이즈

  function Noise(x, y)
    .
    .
  end function

  function SmoothNoise_2D(x>, y)

    corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16
    sides   = ( Noise(x-1, y)  +Noise(x+1, y)  +Noise(x, y-1)  +Noise(x, y+1) ) /  8
    center  =  Noise(x, y) / 4

    return corners + sides + center


  end function

10 모두 합치기

이제 당신은 모두 다 알았다. 당신이 배워온것을 모두 합쳐서 펄린 노이즈 함수를 만들 시간이다. 단지 여러개의 보간된 노이즈 함수를 하나로 더하는 것임을 기억하라. 결국 펄린 노이즈는 단지 하나의 함수인 것이다. 하나이상의 전달인자를 넘기고 함수는 하나의 숫자로 응답한다. 여기 간단한 1차원 펄린 함수가 있다.

펄린 함수의 주된 부분은 루프다. 루프가 반복될 때마다 주파수가 두배가 되는 옥타브를 더한다. 되풀이될때마다 Noisei 로 표기되는 다른 노이즈 함수를 부른다. 이제 휴도코드가 보여주는 것처럼 각각의 옥타브마다 하나씩의 수많은 노이즈 함수를 실제로 쓸 필요는 없다. 3개의 큰 소수 값을 뺀 모든 노이즈 함수는 근본적으로 같기 때문에 똑같은 코드를 유지하던지 아니면 단순히 다른 소수세트를 사용할 수도 있다.

10.1 1차원 펄린 노이즈 Pseudo 코드

  function Noise1(integer x)
    x = (x<<13) ^ x;
    return ( 1.0 - ( (x * (x * x * 15731 + 789221) + 1376312589) & 7fffffff) / 1073741824.0);
  end function


  function SmoothedNoise_1(float x)
    return Noise(x)/2  +  Noise(x-1)/4  +  Noise(x+1)/4
  end function


  function InterpolatedNoise_1(float x)

      integer_X    = int(x)
      fractional_X = x - integer_X

      v1 = SmoothedNoise1(integer_X)
      v2 = SmoothedNoise1(integer_X + 1)

      return Interpolate(v1 , v2 , fractional_X)

  end function


  function PerlinNoise_1D(float x)

      total = 0
      p = persistence
      n = Number_Of_Octaves - 1

      loop i from 0 to n

          frequency = 2i
          amplitude = pi

          total = total + InterpolatedNoisei(x * frequency) * amplitude

      end of i loop

      return total

  end function


이제 똑같은 코드를 2차원 이상의 펄린노이즈 함수에 적용하는것은 쉽다.

10.2 2차원 펄린 노이즈 Pseudo 코드

  function Noise1(integer x, integer y)
    n = x + y * 57
    n = (n<<13) ^ n;
    return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 7fffffff) / 1073741824.0);
  end function

  function SmoothNoise_1(float x, float y)
    corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16
    sides   = ( Noise(x-1, y)  +Noise(x+1, y)  +Noise(x, y-1)  +Noise(x, y+1) ) /  8
    center  =  Noise(x, y) / 4
    return corners + sides + center
  end function

  function InterpolatedNoise_1(float x, float y)

      integer_X    = int(x)
      fractional_X = x - integer_X

      integer_Y    = int(y)
      fractional_Y = y - integer_Y

      v1 = SmoothedNoise1(integer_X,     integer_Y)
      v2 = SmoothedNoise1(integer_X + 1, integer_Y)
      v3 = SmoothedNoise1(integer_X,     integer_Y + 1)
      v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1)

      i1 = Interpolate(v1 , v2 , fractional_X)
      i2 = Interpolate(v3 , v4 , fractional_X)

      return Interpolate(i1 , i2 , fractional_Y)

  end function


  function PerlinNoise_2D(float x, float y)

      total = 0
      p = persistence
      n = Number_Of_Octaves - 1

      loop i from 0 to n

          frequency = 2i
          amplitude = pi

          total = total + InterpolatedNoisei(x * frequency, y * frequency) * amplitude

      end of i loop

      return total

  end function

11 펄린 노이즈의 응용분야

이제 이 멋진 함수를 갖게 됐으니, 이걸로 무엇을 해볼수 있을까? 흠, 상투적으로 생각해보더라도 당신의 상상력만이 이것의 활용분야를 제한한다. 펄린 노이즈는 내가 다 생각해 볼수도 없을 정도로 많은 응용분야를 가지고 있다. 어디 한번 보자.

11.1 1 차원

  • 가상의 무엇을 제어하기 : 살아있는 것들은 매우 오랫동안 가만히 있는일이 드물다.(학생은 빼고) 게임의 예에서 가상 인간 플레이어가 좀더 생동감있게 보이도록 펄린 노이즈를 사용해 그의 관절위치를 부단히 보정해라.

  • 스케치한 선을 그리기 : 컴퓨터가 그린 선은 항상 완벽하게 직선이어서 선이 부자연스럽고 친근감이 들지 않게 만들수 있다. 선이 손으로 그려진것마냥 보이게 만들기 위해 펄린노이즈 사용하여 선그리기 알고리즘에 흔들림을 삽입할수 있다. 구불구불한 원이나 상자를 그리는 것도 가능하다. 스케치 유저 인터페이스를 만들기 위한 몇몇 연구가 행해져 오고 있다.

http://freespace.virgin.net/hugo.elias/models/sketch1.gif


11.2 2 차원

  • 지형 : 2D 펄린 노이즈의 완벽한 응용분야중 하나다. 재분할(subdivision) 방법과는 다르게 메모리 어디에도 지형을 저장할 필요없이 그 지형의 어느지점의 높이든 쉽게 계산해낼수 있다. 게다가 지면은 (거의)무한히 늘려지고 미세한 디테일도 계산될 수 있어 다양한 정도의 디테일 생성에 완벽한 모습을 보여준다. 지형의 특성도 역시 쉽게 정의될 수 있다.

  • 구름 : 또한, 구름생성도 펄린 노이즈에 잘 부합된다.

  • 텍스쳐 생성 : 모든 종류의 텍스쳐가 펄린노이즈를 사용해서 생성될 수 있다. 몇가지 예제로 아래의 테이블을 보라. 생성된 텍스쳐는 (반복된다 해도)반복되기 전에 오랫동안 사용될수 있어서 반복적인 타일 텍스쳐 맵보다 훨씬 더 맘에 들게 만든다.

11.3 3 차원

  • 3D 구름 : 물론 볼륨있는 구름을 만들수도 있다. 이걸 표시하려면은 아마도 몇가지 레이트레이싱을 사용해야만 할 것이다.
  • 움직이는 구름 : 하나의 차원을 시간으로 간주하면, 3D 펄린 노이즈로 움직이는 2차원 구름을 만들수 있다.
  • 속이 비지 않은 텍스쳐 : POVray 같은 몇몇 렌더링 / 레이트레이싱 프로그램은 3차원 텍스쳐로부터 충실하게 깍아낸 텍스쳐를 물체에 적용한다. 이것은 보통 (평평하지 않은) 3D 물체에 2D 텍스쳐를 매핑해 일어나는 일그러짐으로부터 텍스쳐가 상하는 일이 없다는걸 말한다.

11.4 4 차원

  • 움직이는 3D 텍스쳐와 구름 : 고차원으로 올라가면 쉽게 움직이는 구름이나 솔리드 텍스쳐를 생성할수 있다. 단지 여분의 차원을 시간으로 간주하면 된다.

http://freespace.virgin.net/hugo.elias/models/lakedistrict.jpg

Copyright Matt Fairclough 1998. 이 그림에 있는 지형, 구름, 물은 모두 수학적으로 펄린노이즈 생성되었고 [http]Terragen으로 만들어졌다.


이 데모에서 구름은 3D 펄린 노이즈로 움직여진다. 실시간으로 펄린 노이즈를 생성해 내기 위해 알고리즘이 약간 수정되어야만 했다. 어떻게 했는지 더 자세한 정보를 원한다면 [http]Clouds Article을 보라.

12 Perlin Noise 를 이용한 텍스쳐 생성

Perlin을 이용한 텍스쳐 생성은 정말 환상적이다. 여러분은 메모리는 거의 차지하지 않으면서 무한히 큰(모든 실용적 목적으로) 텍스쳐를 생성할수 있다. 여러분은 대리석,나무,소용돌이 무늬등 여러분이 노력한다면 아마도 어떤 것이든 생성할 수 있다. 여러분은 또한 3차원 텍스쳐를 정의할수 있다. 여러분은 이것을 깍아서 어떤 물체를 만들수 있는 재질의 단단한 덩어리로 간주해도 된다. 이는 뒤틀림 없이 어떠한 모양의 물체에도 적용될수 있는 텍스쳐를 생성하게 해준다. 정말 괜찮은 텍스쳐를 얻기위해서는 많은 상상력과 생각, 경험을 필요로하지만 그 결과는 매우 인상적일 것이다.

당신 좋을대로 이리 저리 가지고 놀아보라. 텍스쳐를 만들기 위해 여러 펄린 함수를 사용하라, 여러가지 차원에서 다른 지속성과 주파수로 시도해보라. 여러분은 또다른것의 속성에 영향을 주기위해 하나의 Perlin 함수를 이용할수있다. 함수들을 결과에 적용하자. 여러분이 원하는데로 하라, 그것이 여러분이 꿈꾸는 어떤 텍스쳐를 생성하는 거의 확실한 방법이다.

다음의 텍스쳐는 삼차원 Perlin Noise 로 만들어졌다.


표준 삼차원 Perlin Noise. 4 옥타브, 지속성 0.25 와 0.5


낮은 지속성. 여러분은 결과에 함수를 적용해 Perlin Noise에 날카로운 경계를 생성할수 있다.


더 흥미있고 복잡한 텍스쳐를 생성하기위해 여러분은 여러가지 Perlin 함수들을 섞어 시도해 봐야만한다. 이 텍스쳐는 두 부분으로 생성되었다. 첫번째로 낮은 지속성을 가진 Perlin 함수는 얼룩의 형태를 만드는데 이용되었다. 이 함수의 값은 두가지 다른 함수를 선택하는데 이용되었는데, 하나는 줄무늬를 위해, 다른 하나는 얼룩을 위한 함수이다. 앞부분은 높은 지속성의 함수가 많이 선택되었고, 뒷부분은 낮은 지속성의 함수가 많이 선택되었다. 줄무늬는 어떤 수와( 대략 20 ) 첫번째 Perlin 함수를 곱해서 생성되었고 그 다음 코사인을 취했다.


대리석무늬의 텍스쳐는 Perlin 함수를 코사인 함수에 대한 옵셋(상쇄?)으로 이용해 만들어 질수 있다.

    texture = cosine( x + perlin(x,y,z) )


아주 보기좋은 나무결 텍스쳐들도 만들수 있다. 결은 다음과 같은 낮은 persistence 를 가진 함수에 의해 만들어진다.

    g = perlin(x,y,z) * 20
    grain = g - int(g)

나무에서 볼수 있는 멋진 범프는 일차원에서 늘려져온 높은 주파수의 잡음이다.

    bumps = perlin(x*50, y*50, z*20)
    if bumps < .5 then bumps = 0  else bumps = 1t

13 참고문헌 및 링크

  • Procedural textures : [http]http://developer.intel.com/drg/mmx/appnotes/proctex.htm 인텔 개발자 사이트의 실시간으로 펄린노이즈를 생성하는데 있어 새로운 MMX 기술사용법에 대한 기사
  • Ken Perlin's Homepage : [http]http://mrl.nyu.edu/perlin/ 나는 이 사람이 펄린노이즈에 응답하는게 당연하다고 생각한다. 그는 텍스쳐와 모델링에 대한 수많은 유용한 링크를 가진 흥미로운 페이지를 운영한다.
  • Texturing And Modeling A Procedural Approach: [http]http://www.cs.umbc.edu/~ebert/book/book.html 텍스쳐를 생성하기 위한 또다른 알고리즘과 다양한 자연현상 모델 얘기를 포함한 펄린 노이즈를 사용하는데 대한 깊은 정보가 있는 펄린의 책
  • Procedural Texture Page: [http]http://www.threedgraphics.com/pixelloom/tex_synth.html 이 페이지는 순차적 텍스쳐 합성(Procedural Texture Synthesis)에 관계된 모든 정보와 WWW 링크를 모으려는 시도를 하고 있다.

반응형
반응형


반응형

+ Recent posts