본문 바로가기
LibGdx

libgdx - Convert c ++ bullet file to libgdx file - 1( terrainDemo )

by ses jeon 2019. 12. 14.

Let's port the terrainDemo with reference to basicDemo porting in the previous chapter.

앞장의 basicDemo porting을 참고로 terrainDemo를 porting 해 보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
#include "TerrainDemo.h"
#include "GlutStuff.h"
 
int main(int argc,char** argv)
{
    DemoApplication * demo = btCreateTerrainDemo();
    btAssert(demo && "failed to create terrain demo object");
 
        return glutmain(argc, argv, 800600,
        "Terrain Demo. http://www.continuousphysics.com/Bullet/phpBB2/",
        demo);
}
cs

btCreateTerrainDemo () is executed instead of initPhysics. Follow the source.

initPhysics 대신에 btCreateTerrainDemo()가 실행됩니다. 소스를 따라갑니다.

The world setting is different. This part does not have prior knowledge of the bullet wrapper reference. Originally it was where btDbvtBroadphase ();

world 세팅이 달라집니다. 이 부분은 bullet wrapper 참고서에서의 사전 지식이 없습니다. 원래는 btDbvtBroadphase();가 있던 부분입니다. 

..... 추가

 

I'm changing 1- gravity, creating 2-btHeightFiledData, and 3- btHeightFiledTerrainShape.
I think you need to understand the new btHeightFiledData, btHeightFieldTerrainShape. Other work flows are no different from the dynamic world settings.

First, let's check the other terrainDemo part.

1- gravity를 변경하고, 2 - btHeightFiledData 를 만들고, 3- btHeightFiledTerrainShape 를 생성하고 있습니다.

새로 나온 btHeightFiledData , btHeightFieldTerrainShape 에 대한 이해가 필요할것 같습니다. 그외의 work flow는 지금까지의 dynamic world 세팅과 다를바 없습니다.

 

먼저 그 외의 terrainDemo 부분을 체크해 보겠습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// creates a radially-varying heightfield
static void
setRadial
(
byte_t * grid,
int bytesPerElement,
PHY_ScalarType type,
float phase = 0.0
)
{
    btAssert(grid);
    btAssert(bytesPerElement > 0);
 
    // min/max
    float period = 0.5 / s_gridSpacing;
    float floor = 0.0;
    float min_r = 3.0 * sqrt(s_gridSpacing);
    float magnitude = 50.0 * sqrt(s_gridSpacing);
 
    // pick a base_phase such that phase = 0 results in max height
    //   (this way, if you create a heightfield with phase = 0,
    //    you can rely on the min/max heights that result)
    float base_phase = (0.5 * SIMD_PI) - (period * min_r);
    phase += base_phase;
 
    // center of grid
    float cx = 0.5 * s_gridSize * s_gridSpacing;
    float cy = cx;        // assume square grid
    byte_t * p = grid;
    for (int i = 0; i < s_gridSize; ++i) {
        float x = i * s_gridSpacing;
        for (int j = 0; j < s_gridSize; ++j) {
            float y = j * s_gridSpacing;
 
            float dx = x - cx;
            float dy = y - cy;
 
            float r = sqrt((dx * dx) + (dy * dy));
 
            float z = period;
            if (r < min_r) {
                r = min_r;
            }
            z = (1.0 / r) * sin(period * r + phase);
            if (z > period) {
                z = period;
            } else if (z < -period) {
                z = -period;
            }
            z = floor + magnitude * z;
 
            convertFromFloat(p, z, type);
            p += bytesPerElement;
        }
    }
}
cs

It is said to create radial change terrain. We can infer that we take a grid of bype_t * type that we don't know yet and change it. The last part can be read as changing p (since it's a grid) and shifting it by the data size.

방사형 변화 terrain 을 만든다고 나와있습니다. 우리가 아직 잘 모르는 bype_t* 형의 grid를 받아서 그것을 변화시켜준다고 유추할수 있습니다.  마지막 부분은 p를 변화시키고(그것은 grid 이니까) 데이터 크기만큼 이동시킨다고 읽을수 있겠네요.

convertFromFloat(p, z, type);

p += bytesPerElement;

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// creates a random, fractal heightfield
static void
setFractal
(
byte_t * grid,
int bytesPerElement,
PHY_ScalarType type,
int step
)
{
    btAssert(grid);
    btAssert(bytesPerElement > 0);
    btAssert(step > 0);
    btAssert(step < s_gridSize);
 
    int newStep = step / 2;
//    std::cerr << "Computing grid with step = " << step << ": before\n";
//    dumpGrid(grid, bytesPerElement, type, step + 1);
 
    // special case: starting (must set four corners)
    if (s_gridSize - 1 == step) {
        // pick a non-zero (possibly negative) base elevation for testing
        float base = randomHeight(step / 2);
 
        convertFromFloat(grid, base, type);
        convertFromFloat(grid + step * bytesPerElement, base, type);
        convertFromFloat(grid + step * s_gridSize * bytesPerElement, base, type);
        convertFromFloat(grid + (step * s_gridSize + step) * bytesPerElement, base, type);
    }
 
    // determine elevation of each corner
    float c00 = convertToFloat(grid, type);
    float c01 = convertToFloat(grid + step * bytesPerElement, type);
    float c10 = convertToFloat(grid + (step * s_gridSize) * bytesPerElement, type);
    float c11 = convertToFloat(grid + (step * s_gridSize + step) * bytesPerElement, type);
 
    // set top middle
    updateHeight(grid + newStep * bytesPerElement, 0.5 * (c00 + c01) + randomHeight(step), type);
 
    // set left middle
    updateHeight(grid + (newStep * s_gridSize) * bytesPerElement, 0.5 * (c00 + c10) + randomHeight(step), type);
 
    // set right middle
    updateHeight(grid + (newStep * s_gridSize + step) * bytesPerElement, 0.5 * (c01 + c11) + randomHeight(step), type);
 
    // set bottom middle
    updateHeight(grid + (step * s_gridSize + newStep) * bytesPerElement, 0.5 * (c10 + c11) + randomHeight(step), type);
 
    // set middle
    updateHeight(grid + (newStep * s_gridSize + newStep) * bytesPerElement, 0.25 * (c00 + c01 + c10 + c11) + randomHeight(step), type);
 
//    std::cerr << "Computing grid with step = " << step << ": after\n";
//    dumpGrid(grid, bytesPerElement, type, step + 1);
 
    // terminate?
    if (newStep < 2) {
        return;
    }
 
    // recurse
    setFractal(grid, bytesPerElement, type, newStep);
    setFractal(grid + newStep * bytesPerElement, bytesPerElement, type, newStep);
    setFractal(grid + (newStep * s_gridSize) * bytesPerElement, bytesPerElement, type, newStep);
    setFractal(grid + ((newStep * s_gridSize) + newStep) * bytesPerElement, bytesPerElement, type, newStep);
}
cs

Creates a random fractal height field.

setRadial () and setFractal () This doesn't know exactly what it does, but it can be expected to transform the grid data anyway. When you run the example, the ground is moving, so it seems to be the same.

임의의 프랙탈 높이 필드를 만듭니다. 

 

setRadial()과 setFractal() 이것은 그 내용은 정확히 모르지만, 어쨋든 grid라는 데이터를 변형시켜준다고 예상할수 있습니다. 예제를 실행시켜보면 지면이 움직이니까 그것만 일맥상통하는것 같습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
static byte_t *
getRawHeightfieldData
(
eTerrainModel model,
PHY_ScalarType type,
btScalar& minHeight,
btScalar& maxHeight
)
{
//    std::cerr << "\nRegenerating terrain\n";
//    std::cerr << "  model = " << model << "\n";
//    std::cerr << "  type = " << type << "\n";
 
    long nElements = ((long) s_gridSize) * s_gridSize;
//    std::cerr << "  nElements = " << nElements << "\n";
 
    int bytesPerElement = getByteSize(type);
//    std::cerr << "  bytesPerElement = " << bytesPerElement << "\n";
    btAssert(bytesPerElement > 0 && "bad bytes per element");
 
    long nBytes = nElements * bytesPerElement;
//    std::cerr << "  nBytes = " << nBytes << "\n";
    byte_t * raw = new byte_t[nBytes];
    btAssert(raw && "out of memory");
 
    // reseed randomization every 30 seconds
//    srand(time(NULL) / 30);
 
    // populate based on model
    switch (model) {
    case eRadial:
        setRadial(raw, bytesPerElement, type);
        break;
 
    case eFractal:
        for (int i = 0; i < nBytes; i++)
        {
            raw[i] = 0;
        }
        setFractal(raw, bytesPerElement, type, s_gridSize - 1);
        break;
 
    default:
        btAssert(!"bad model type");
    }
 
    if (0) {
        // inside if(0) so it keeps compiling but isn't
        //     exercised and doesn't cause warnings
//        std::cerr << "final grid:\n";
        dumpGrid(raw, bytesPerElement, type, s_gridSize - 1);
    }
 
    // find min/max
    for (int i = 0; i < s_gridSize; ++i) {
        for (int j = 0; j < s_gridSize; ++j) {
            float z = getGridHeight(raw, i, j, type);
//            std::cerr << "i=" << i << ", j=" << j << ": z=" << z << "\n";
 
            // update min/max
            if (!&& !j) {
                minHeight = z;
                maxHeight = z;
            } else {
                if (z < minHeight) {
                    minHeight = z;
                }
                if (z > maxHeight) {
                    maxHeight = z;
                }
            }
        }
    }
 
    if (maxHeight < -minHeight) {
        maxHeight = -minHeight;
    }
    if (minHeight > -maxHeight) {
        minHeight = -maxHeight;
    }
 
//    std::cerr << "  minHeight = " << minHeight << "\n";
//    std::cerr << "  maxHeight = " << maxHeight << "\n";
 
    return raw;
}
cs

getRawHeightfieldData (), yes it seems to be a function that creates heightFieldData directly. But no data is received. You can see that it creates an empty data array called raw. By creating this, it seems to create terrain randomly with the above two functions.

We have looked at the main functions. Now, use your imagination to port the code above to libgdx / java, modify it, and see the value.

This part of drawOpenGL in GL_ShapeDrawer.cpp ..-> Move while watching getShapeType ()

By the way, getShapeType () did not find anything special. Then let's follow the same from the first world setting.

getRawHeightfieldData() , 네 직접 heightFieldData를 만드는 함수인것 같습니다. 그런데 어떤 데이터를 받지는 않습니다. 다만 raw라는 빈 데이터 배열을 만드는것을 알수 있습니다. 이렇게 생성해서, 위의 두 함수로써 임의로 지형을 만드는것 같습니다.

 

주요 함수를 다 살펴보았습니다. 이제는 상상력을 발휘하여 적당히 libgdx/java 에 위에 해당하는 코드를 포팅하여서 수정을 거치며, 값을 확인해야될것 같습니다.

 

GL_ShapeDrawer.cpp 의 drawOpenGL 이부분....-> 이걸 보면된다. getShapeType() 을 보면서 이동

 

그런데  getShapeType()에서는 특별한 곳을 찾지는 못했습니다. 그러면 일단 최초의 world setting 부터 똑같이 쫓아가보도록 하겠습니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

댓글