honglab 그래픽스 1챕터 ~ 2.5 챕터(래스터라이저)까지 듣고 만들어본 프로젝트
https://github.com/cakememakeme/ProjectCpuRender

 CpuRender의 작업물을 SimpleRenderer로 이전 (CpuRenderer 이후 D3D11 Renderer 제작 중)

https://github.com/cakememakeme/SimpleRenderer

 

GitHub - cakememakeme/SimpleRenderer: 이런 저런 렌더링 공부용 렌더러

이런 저런 렌더링 공부용 렌더러. Contribute to cakememakeme/SimpleRenderer development by creating an account on GitHub.

github.com


주요 로직은 CpuRenderPipeline::drawMeshed() 에서 파이프라이닝이 시작된다

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
void CpuRenderPipeline::drawMeshes()
{
    if (meshes.empty())
    {
        std::cout << "invalid meshes." << std::endl;
        return;
    }
 
    // 실제 파이프라인은
    // 1. Input assembler
    // 2. Vertex shader
    // 3. Tessellation
    // 4. Geometry shader
    // 5. Rasterization
    // 6. Fragment shader
    // 7. Color blending
    // 기준으로 되어 있다(Vulkan tutorial 기준)
    // 원래대로라면, Vertex buffer/Index buffer에 있는 버텍스를 3개로 묶어서(Input assemble) 
    // 묶인 단위만큼 파이프라인에 태워 보내는게 맞으나
    // 렌더링에 대해서 직관적으로 파악 가능하게끔, 버퍼 단위가 아닌 메시 단위로 나눠서 보낸다
    for (const auto mesh : meshes)
    {
        if (!mesh)
        {
            continue;
        }
 
        copyToBuffer(*mesh);
        
        for (size_t i = 0; i < g_vertexBuffer.size(); ++i)
        {
            VsInput vsInput;
            vsInput.Position = g_vertexBuffer[i];
            vsInput.normal = g_normalBuffer[i];
 
            // vertex shader 단계
            VsOutput vsOutput = CpuShader::CpuVertexShader(vsInput);
 
            g_vertexBuffer[i] = vsOutput.Position;
            g_normalBuffer[i] = vsOutput.normal;
        }
 
        // rasterize 단계
// 3개 씩 묶어서 전달, (Input assemble) 원래 이게 vertex shader보다 먼저 이뤄져야 한다
        for (size_t i = 0; i < g_indexBuffer.size(); i += 3)
        {
            CpuRasterizer::DrawIndexedTriangle(i);
        }
    }
 
    meshes.clear();
}
cs


CpuRasterizer.cpp 의 DrawIndexedTriangle() 함수

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
void DrawIndexedTriangle(const size_t startIndex)
{
    const size_t i0 = g_indexBuffer[startIndex];
    const size_t i1 = g_indexBuffer[startIndex + 1];
    const size_t i2 = g_indexBuffer[startIndex + 2];
 
    const Vector3& rootV0_clip = worldToClip(g_vertexBuffer[i0]);
    const Vector3& rootV1_clip = worldToClip(g_vertexBuffer[i1]);
    const Vector3& rootV2_clip = worldToClip(g_vertexBuffer[i2]);
 
    const Vector2& rootV0_screen = clipToScreen(rootV0_clip);
    const Vector2& rootV1_screen = clipToScreen(rootV1_clip);
    const Vector2& rootV2_screen = clipToScreen(rootV2_clip);
 
    // 삼각형 전체 넓이의 두 배, 음수일 수도 있음
    const float area = edgeFunction(rootV0_screen, rootV1_screen, rootV2_screen);
 
    // 뒷면일 경우
    if (g_cullBackface && area < 0.0f)
    {
        return;
    }
 
    // clipping
    // 캐시에는 쥐약이겠지만 개발 편의를 위해
    std::list<struct Triangle> triangles;
    triangles.push_back({ rootV0_clip, rootV1_clip, rootV2_clip });
    clipTriangle(triangles);
 
    /*const auto& c0 = g_colorBuffer[i0];
    const auto& c1 = g_colorBuffer[i1];
    const auto& c2 = g_colorBuffer[i2];*/
 
    const Vector2& uv0 = g_uvBuffer[i0];
    const Vector2& uv1 = g_uvBuffer[i1];
    const Vector2& uv2 = g_uvBuffer[i2];
 
    // draw internal
    for (const auto& triangle : triangles)
    {
        const Vector2& v0_screen = clipToScreen(triangle.v0);
        const Vector2& v1_screen = clipToScreen(triangle.v1);
        const Vector2& v2_screen = clipToScreen(triangle.v2);
 
        const Vector2& leftTopPos = Vector2::Min(Vector2::Min(v0_screen, v1_screen), v2_screen);
        const Vector2& rightBotPos = Vector2::Max(Vector2::Max(v0_screen, v1_screen), v2_screen);
 
        const auto xMin = size_t(std::clamp(std::floor(leftTopPos.x), 0.0f, float(g_width - 1)));
        const auto yMin = size_t(std::clamp(std::floor(leftTopPos.y), 0.0f, float(g_height - 1)));
        const auto xMax = size_t(std::clamp(std::ceil(rightBotPos.x), 0.0f, float(g_width - 1)));
        const auto yMax = size_t(std::clamp(std::ceil(rightBotPos.y), 0.0f, float(g_height - 1)));
 
        // Primitive 보간 후 Pixel(Fragment) Shader로 넘긴다
        for (size_t y = yMin; y <= yMax; y++)
        {
            for (size_t x = xMin; x <= xMax; x++)
            {
                const Vector2& point = Vector2(float(x), float(y));
 
                // 위에서 계산한 삼각형 전체 넓이 area를 재사용
                float w0 = edgeFunction(v1_screen, v2_screen, point) / area;
                float w1 = edgeFunction(v2_screen, v0_screen, point) / area;
                float w2 = edgeFunction(v0_screen, v1_screen, point) / area;
 
                // backface culling
                if (w0 >= 0.0f && w1 >= 0.0f && w2 >= 0.0f)
                {
                    // Perspective-Correct Interpolation
                    // OpenGL 구현
                    // https://stackoverflow.com/questions/24441631/how-exactly-does-opengl-do-perspectively-correct-linear-interpolation
 
                    const float z0 = g_vertexBuffer[i0].z + g_distEyeToScreen;
                    const float z1 = g_vertexBuffer[i1].z + g_distEyeToScreen;
                    const float z2 = g_vertexBuffer[i2].z + g_distEyeToScreen;
 
                    const Vector3& p0 = g_vertexBuffer[i0];
                    const Vector3& p1 = g_vertexBuffer[i1];
                    const Vector3& p2 = g_vertexBuffer[i2];
 
                    // 뒷면일 경우에도 쉐이딩이 가능하도록 normal을 반대로
                    /*const Vector3& n0 = area < 0.0f ? -g_normalBuffer[i0] : g_normalBuffer[i0];
                    const Vector3& n1 = area < 0.0f ? -g_normalBuffer[i1] : g_normalBuffer[i1];
                    const Vector3& n2 = area < 0.0f ? -g_normalBuffer[i2] : g_normalBuffer[i2];*/
                    const Vector3& n0 = g_normalBuffer[i0];
                    const Vector3& n1 = g_normalBuffer[i1];
                    const Vector3& n2 = g_normalBuffer[i2];
 
                    if (g_bUsePerspectiveProjection)
                    {
                        w0 /= z0;
                        w1 /= z1;
                        w2 /= z2;
 
                        const float wSum = w0 + w1 + w2;
 
                        w0 /= wSum;
                        w1 /= wSum;
                        w2 /= wSum;
                    }
 
                    const float depth = w0 * z0 + w1 * z1 + w2 * z2;
                    const Vector2& uv = w0 * uv0 + w1 * uv1 + w2 * uv2;
 
                    if (depth < g_depthBuffer[x + g_width * y])
                    {
                        g_depthBuffer[x + g_width * y] = depth;
 
                        PsInput psInput;
                        psInput.Position = w0 * p0 + w1 * p1 + w2 * p2;
                        psInput.normal = w0 * n0 + w1 * n1 + w2 * n2;
                        psInput.uv = uv;
 
                        std::vector<Vector4>& buffer = g_displayBuffer;
                        buffer[x + g_width * y] = CpuShader::CpuPixelShader(psInput);
                    }
                }
            }
        }
    }
}
cs

 

클리핑 함수 clipTriangle() / splitTriangle()

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
void clipTriangle(std::list<struct Triangle>& triangles)
{
    using namespace std;
 
    list<struct Triangle>::iterator eraseMark = triangles.end();
    for (auto triangle = triangles.begin(); triangle != triangles.end(); ++triangle)
    {
        if (eraseMark != triangles.end())
        {
            triangles.erase(eraseMark);
            eraseMark = triangles.end();
        }
 
        const struct Triangle& tri = *triangle;
 
        // far plane 제외하고 클리핑을 수행
        const Vector4& nearClippingPlane = Vector4{ 0.0f, 0.0f, g_distEyeToScreen, -g_nearClip };
        const EPlaceFromPlane nearPlane = intersectPlaneAndTriangle(nearClippingPlane, tri);
        if (nearPlane != EPlaceFromPlane::Inside)
        {
            eraseMark = triangle;
            if (nearPlane == EPlaceFromPlane::Middle)
            {
                triangles.splice(triangles.end(), splitTriangle(nearClippingPlane, tri));
            }
            continue;
        }
 
        const Vector4& leftClippingPlane = Vector4{ 1.0f, 0.0f, 0.0f, g_leftClip };
        const EPlaceFromPlane left = intersectPlaneAndTriangle(leftClippingPlane, tri);
        if (left != EPlaceFromPlane::Inside)
        {
            eraseMark = triangle;
            if (left == EPlaceFromPlane::Middle)
            {
                triangles.splice(triangles.end(), splitTriangle(leftClippingPlane, tri));
            }
            continue;
        }
 
        const Vector4& rightClippingPlane = Vector4{ -1.0f, 0.0f, 0.0f, g_rightClip };
        const EPlaceFromPlane right = intersectPlaneAndTriangle(rightClippingPlane, tri);
        if (right != EPlaceFromPlane::Inside)
        {
            eraseMark = triangle;
            if (right == EPlaceFromPlane::Middle)
            {
                triangles.splice(triangles.end(), splitTriangle(rightClippingPlane, tri));
            }
            continue;
        }
        const Vector4& topClippingPlane = Vector4{ 0.0f, -1.0f, 0.0f, g_topClip };
        const EPlaceFromPlane top = intersectPlaneAndTriangle(topClippingPlane, tri);
        if (top != EPlaceFromPlane::Inside)
        {
            eraseMark = triangle;
            if (top == EPlaceFromPlane::Middle)
            {
                triangles.splice(triangles.end(), splitTriangle(topClippingPlane, tri));
            }
            continue;
        }
        const Vector4& bottomClippingPlane = Vector4{ 0.0f, 1.0f, 0.0f, g_bottomClip };
        const EPlaceFromPlane bottom = intersectPlaneAndTriangle(bottomClippingPlane, tri);
        if (bottom != EPlaceFromPlane::Inside)
        {
            eraseMark = triangle;
            if (bottom == EPlaceFromPlane::Middle)
            {
                triangles.splice(triangles.end(), splitTriangle(bottomClippingPlane, tri));
            }
            continue;
        }
    }
 
    if (eraseMark != triangles.end())
    {
        triangles.erase(eraseMark);
        eraseMark = triangles.end();
    }
}
cs

 

splitTriangle()

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
td::list<struct Triangle> splitTriangle(const DirectX::SimpleMath::Vector4& plane, const Triangle& triangle)
{
    // 주의: 버텍스의 시계방향 순서(CW)는 유지되나, 좌하단 -> 좌상단 -> 우상단의 순서는 깨지게 됩니다
    // 한 칸씩 밀립니다
    const struct Triangle& tri = triangle;
    std::array<Vector3, 3> tris = { tri.v0, tri.v1, tri.v2 };
    std::vector<Vector3> splitTri_inside;
    splitTri_inside.reserve(4);
    std::vector<Vector3> splitTri_outside;
    splitTri_outside.reserve(4);
 
    switch (findVertexPlace(intersectPlaneAndVertex(plane, tris[0])))
    {
    case EPlaceFromPlane::Inside:
    {
        splitTri_inside.push_back(tris[0]);
    }
    break;
    case EPlaceFromPlane::Outside:
    {
        splitTri_outside.push_back(tris[0]);
    }
    break;
    case EPlaceFromPlane::Middle:
    {
        splitTri_inside.push_back(tris[0]);
        splitTri_outside.push_back(tris[0]);
    }
    break;
    default:
    {
 
    }
    }
 
    for (size_t i = 1; i <= tris.size(); ++i)
    {
        const size_t currIdx = i % 3;
        const Vector3& prevVert = tris[i - 1];
        const Vector3& currVert = tris[currIdx];
 
        const float dist = intersectPlaneAndVertex(plane, currVert);
        const EPlaceFromPlane currPlace = findVertexPlace(dist);
        if (currPlace == EPlaceFromPlane::Middle)
        {
            splitTri_inside.push_back(currVert);
            splitTri_outside.push_back(currVert);
        }
        else
        {
            Vector3 intersectPoint = Vector3::Zero;
            if (intersectPlaneAndLine(intersectPoint, plane, prevVert, currVert))
            {
                if (currPlace == EPlaceFromPlane::Inside)
                {
                    splitTri_outside.push_back(intersectPoint);
                    splitTri_inside.push_back(intersectPoint);
                    if (currIdx != 0)
                    {
                        splitTri_inside.push_back(currVert);
                    }
                }
                if (currPlace == EPlaceFromPlane::Outside)
                {
                    splitTri_inside.push_back(intersectPoint);
                    splitTri_outside.push_back(intersectPoint);
                    if (currIdx != 0)
                    {
                        splitTri_outside.push_back(currVert);
                    }
                }
            }
            else
            {
                if (currPlace == EPlaceFromPlane::Inside)
                {
                    splitTri_inside.push_back(currVert);
                }
                if (currPlace == EPlaceFromPlane::Outside)
                {
                    splitTri_outside.push_back(currVert);
                }
            }
        }
    }
 
    /*
    if(splitTri_inside.size() < 3)
    {
        const EPlaceFromPlane top = intersectPlaneAndTriangle(plane, tri);
        int bp = 0;
    }
    if (splitTri_inside.size() > 4 || splitTri_outside.size() > 5)
    {
        const EPlaceFromPlane top = intersectPlaneAndTriangle(plane, tri);
        int bp = 0;
    }
    std::cout << splitTri_inside.size() << ' ' << splitTri_outside.size() << '\n';
    */
    std::list<struct Triangle> insideTris;
    if (splitTri_inside.size() == splitTri_outside.size())
    {
        Triangle insideTri;
        insideTri.v0 = splitTri_inside[0];
        insideTri.v1 = splitTri_inside[1];
        insideTri.v2 = splitTri_inside[2];
        insideTris.push_back(insideTri);
 
        /*Triangle outsideTri;
        outsideTri.v0 = splitTri_outside[0];
        outsideTri.v1 = splitTri_outside[1];
        outsideTri.v2 = splitTri_outside[2];*/
    }
    else if (splitTri_inside.size() > splitTri_outside.size())
    {
        Triangle insideTri0;
        insideTri0.v0 = splitTri_inside[0];
        insideTri0.v1 = splitTri_inside[1];
        insideTri0.v2 = splitTri_inside[2];
        insideTris.push_back(insideTri0);
 
        Triangle insideTri1;
        insideTri1.v0 = splitTri_inside[0];
        insideTri1.v1 = splitTri_inside[2];
        insideTri1.v2 = splitTri_inside[3];
        insideTris.push_back(insideTri1);
 
        /*Triangle outsideTri;
        outsideTri.v0 = splitTri_outside[0];
        outsideTri.v1 = splitTri_outside[1];
        outsideTri.v2 = splitTri_outside[2];*/
    }
    else
    {
        /*Triangle outsideTri0;
        outsideTri0.v0 = splitTri_outside[0];
        outsideTri0.v1 = splitTri_outside[1];
        outsideTri0.v2 = splitTri_outside[2];
 
        Triangle outsideTri1;
        outsideTri1.v0 = splitTri_outside[0];
        outsideTri1.v1 = splitTri_outside[2];
        outsideTri1.v2 = splitTri_outside[3];*/
 
        Triangle insideTri;
        insideTri.v0 = splitTri_inside[0];
        insideTri.v1 = splitTri_inside[1];
        insideTri.v2 = splitTri_inside[2];
        insideTris.push_back(insideTri);
    }
 
    return insideTris;
}
cs



 

 

클리핑이 된다

3ds Max, Adobe Photoshop

개틀링은 협찬이다

선글라스 빛줄기는 텍스처로 그렸다ㅎ

구리구리한 라이팅에서 당시 시대상을 잘 느낄 수 있다

'개인 작업 > Art' 카테고리의 다른 글

연필(2017?)  (0) 2023.04.29
로우폴리_1(2017)  (0) 2023.04.29

트레이싱이지만 엄청 공들여서 베꼈다

그림 주변에 묻은 손때가 그걸 증명한다

'개인 작업 > Art' 카테고리의 다른 글

피카츄(2016)  (0) 2023.04.29
로우폴리_1(2017)  (0) 2023.04.29

ㅎㅎ...

지금 하면 더 잘할텐데

'개인 작업 > Art' 카테고리의 다른 글

피카츄(2016)  (0) 2023.04.29
연필(2017?)  (0) 2023.04.29

https://mm5-gnap.tistory.com/390

 

노말 매핑, 시차 매핑(parallax mapping)

 

mm5-gnap.tistory.com

여기에 어느정도는 설명되어 있다

https://mm5-gnap.tistory.com/412

 

메시 디스턴스 필드(미완)

공부중입니다

mm5-gnap.tistory.com

물체의 가장자리에 거품이 생겼다

 

좋았던 점

게임 개발을 시작하면서 가진 꿈 중에 하나가 바다를 만들어보는 것이었는데, 이번 기회에 어느정도? 해소하게 된 것 같다

 

아쉬운 점

퀄리티가 마음에 들지 않는다... 파도 거품도 어색하고, 진짜 파도같지도 않고

원래 목표는 water buoyancy까지 적용해서 물체를 물에 집어넣으면 떠오르고, 그로 인해 메시가 물결치는 것도 구현 목표였는데, 일도 해야하고, 다른 공부도 산더미처럼 쌓여있다 보니 다 하지는 못했다

진짜 만족할만한 수준의 바다 셰이더는 좀 더 실력을 쌓아야 할 것 같다. 앞으로 Participating media rendering 공부하면서 유체쪽 건드릴 것 같은데, 강해지고 난 뒤 다시 도전해야겠다

https://www.youtube.com/watch?v=svQusHq4_tU 

바다 구현의 최종 목표...!

언젠가는...

 

업데이트 패턴이라는 이름이 붙기 전부터 그냥 Tick이라는 개념으로 사용되어 왔다

 

UE5의 틱 방식도 크게 변화하진 않았을거라 생각하는데, 이 부분은 확인이 필요하다. 위에 재확인 필요한 틱 의존성 관련 부분도 겸사겸사 같이 살펴볼 예정

공부중입니다

메시 디스턴스 필드가 추가된 바다 머티리얼

'그래픽스' 카테고리의 다른 글

그래픽스 자료 정리  (0) 2021.06.30
교차판정과 레이 트레이싱, OBB 이론  (0) 2021.03.03
텍스처  (0) 2020.12.09
시저 테스트  (0) 2020.11.29
래스터라이저  (0) 2020.11.29

공부&정리중입니다

'프로그래밍' 카테고리의 다른 글

COM  (0) 2020.11.06
XML, XML DOM  (0) 2020.11.06
기본적인 어셈블러 레지스터  (0) 2019.08.27
FSM  (0) 2019.07.24
더블과 플로트, FPU에 관해 (6 / 2)  (0) 2019.06.09

'알고리즘' 카테고리의 다른 글

백준 2805 : 나무 자르기  (0) 2021.04.18
백준 13397 : 구간 나누기 2  (0) 2021.04.16
백준 1654 : 랜선 자르기  (0) 2021.04.16
백준 1477 : 휴게소 세우기  (0) 2021.04.15
백준 2470 / 2467 : 두 용액 / 용액  (0) 2021.04.14

 

현재 그래픽스란의 글이 보기 불편하다고 느껴져 일단 링크별로 정리해봤습니다

더 좋은 방법을 찾으면 다른 방향으로 정리해보겠습니다...

 



법선 매핑(Normal mapping)과 시차 매핑(Parallax mapping)

mm5-gnap.tistory.com/390

 

노말 매핑, 시차 매핑(parallax mapping)

 

mm5-gnap.tistory.com

 

셰이더 프로그래밍과 그림자 매핑

mm5-gnap.tistory.com/392

 

셰이더 프로그래밍과 그림자 매핑

 

mm5-gnap.tistory.com

 

렌더링 파이프라인과 셰이더

mm5-gnap.tistory.com/393

 

렌더링 파이프라인과 셰이더

 

mm5-gnap.tistory.com

 

텍스처링, 빌보드, 높이맵을 사용한 지형 생성

mm5-gnap.tistory.com/391

 

텍스처링, 빌보드, 높이맵을 사용한 지형 생성

 

mm5-gnap.tistory.com

 

지형 처리 1 - 절두체 컬링과 쿼드트리 컬링

mm5-gnap.tistory.com/322

 

쿼드트리와 절두체 컬링

 

mm5-gnap.tistory.com

 

지형 처리 2 - LOD와 균열방지

mm5-gnap.tistory.com/394

 

LOD와 균열방지

 

mm5-gnap.tistory.com

 

임의의 축 회전과 사원수, 사원수 회전, 구면선형보간

mm5-gnap.tistory.com/338

 

회전과 사원수

 

mm5-gnap.tistory.com

 

캐릭터 애니메이션 1 - 이론(계층 구조, 키프레임 애니메이션, 스키닝 애니메이션)

mm5-gnap.tistory.com/395

 

캐릭터 애니메이션 1 - 이론

(계층 구조, 키프레임 애니메이션, 스키닝 애니메이션)

mm5-gnap.tistory.com

 

캐릭터 애니메이션 2 - 소스(계층 구조, 키프레임 애니메이션, 스키닝 애니메이션)

mm5-gnap.tistory.com/396

 

캐릭터 애니메이션 2 - 소스 (1 / 2)

 (계층 구조, 키프레임 애니메이션, 스키닝 애니메이션) mm5-gnap.tistory.com/397 캐릭터 애니메이션 2 - 소스 (2 / 2) mm5-gnap.tistory.com

mm5-gnap.tistory.com

 

내부지형 처리 1 - BSP 트리 이론 (오브젝트 환경 충돌처리)

mm5-gnap.tistory.com/398

 

내부지형 처리 1 - BSP 트리 이론

오브젝트 환경 충돌처리

mm5-gnap.tistory.com

 

내부지형 처리 2 - BSP 트리 소스 (오브젝트 환경 충돌처리)

mm5-gnap.tistory.com/399

 

내부지형 처리 2 - BSP 트리 소스

오브젝트 환경 충돌처리

mm5-gnap.tistory.com

https://mm5-gnap.tistory.com/358

 

교차판정과 레이 트레이싱, OBB 이론

 

mm5-gnap.tistory.com

 

.

'그래픽스' 카테고리의 다른 글

메시 디스턴스 필드(미완)  (0) 2023.03.01
교차판정과 레이 트레이싱, OBB 이론  (0) 2021.03.03
텍스처  (0) 2020.12.09
시저 테스트  (0) 2020.11.29
래스터라이저  (0) 2020.11.29

https://unrealengine.tistory.com/44

 

언리얼 네트워크 정리

Network Conpendium의 요약정리 자료를 참고하여 정리하는 과정에서 작성자의 오해나 이해가 부족한 점이 있을 수 있음을 알려드립니다 Network Multiplayers 게임관련 주요 클래스 GameInstance GameMode GameSta..

unrealengine.tistory.com

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=cloud2ind&logNo=220868582478 

 

UE4 :: Replication

서버와 클라이언트 사이에서 데이터와 명령을 주고받는 프로세스테스트를 위한 에디터 옵션 멀티플레이어 ...

blog.naver.com

https://docs.unrealengine.com/4.26/ko/InteractiveExperiences/Networking/Overview/

 

네트워크 개요

멀티플레이어용 네트워크 게임 구성하기 입니다.

docs.unrealengine.com

https://sites.google.com/site/techaht/trans/unreal-net-arch

 

techaht - 언리얼 네트워킹 아키텍처

원문: http://unreal.epicgames.com/Network.htm 저자: 팀 스위니(Tim Sweeny) 기록: 2007년 5월 - 최초 번역 2011년 2월 - 갱신 (사소한 수정) 2011년 4월 - 최종 정리 Tim Sweeney Epic MegaGames, Inc. http://www.epicgames.com/ Audience

sites.google.com

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=stein84&logNo=10121586146 

 

Role

replication에 쓰이는 개념이다. 액터는 네트웍 게임 내 서버와 클라에서 각각의 값을 가진다 ( Role과 R...

blog.naver.com

https://noooong1231.tistory.com/97

 

[UE4/네트워크] 네트워킹과 멀티플레이어

1. 액터 리플리케이션 리플리케이션의 주역은 Actor이다. 서버는 엑터 목록을 유지하고, 클라이언트(리플리케이트되도록 마킹된) 각 에터에 대한 근접 추정치를 유지할 수 있또록 클라이언트를

noooong1231.tistory.com

https://redchiken.tistory.com/250?category=875940 

 

UE4 Actor의 Role과 Remote Role

Q: Actor의 Role과 Remote Role에 대해 설명하라 A: Role은 Actor에 대한 Authority Owner Actor의 Replication 여부, Remote Role은 Replication Mode를 나타낸다. 특정 Actor의 Authority를 알아내기 위해 Role..

redchiken.tistory.com

https://docs.unrealengine.com/4.26/ko/InteractiveExperiences/Networking/Actors/Roles/

 

액터 롤 및 리모트 롤

액터 오브젝트 리플리케이션의 여러가지 부분에 대한 것입니다.

docs.unrealengine.com

 

정리된 자료는 곧 PPT로 작성됩니다...!

+ Recent posts