개인적으로 Draw 클래스를 Object 클래스 자체에서 유지하는 것이 좋습니다. 객체 위치 / 좌표를 객체 자체에서 멀리 유지하는 것이 좋습니다.
그 draw () 메소드는 OpenGL, OpenGL ES, Direct3D의 저수준 렌더링 API, 해당 API 또는 엔진 API의 래핑 레이어를 처리합니다. 예를 들어 OpenGL + OpenGL ES + Direct3D를 지원하려면 그 사이를 전환해야 할 수도 있습니다.
해당 GameObject에는 메시 또는 셰이더 입력, 애니메이션 상태 등 더 큰 번들과 같은 시각적 모양에 대한 기본 정보 만 포함해야합니다.
또한 유연한 그래픽 파이프 라인을 원할 것입니다. 카메라와의 거리를 기준으로 개체를 주문하려는 경우 어떻게됩니까? 또는 재료 유형. '선택된'객체를 다른 색상으로 그리려면 어떻게됩니까? 객체에서 draw 함수를 호출 할 때 실제로 soo로 끝나는 대신 렌더가 수행 할 액션의 명령 목록에 추가합니다 (스레딩에 필요할 수 있음). 다른 시스템에서도 그런 일을 할 수 있지만 PITA입니다.
내가 권장하는 것은 직접 그리는 대신 원하는 모든 객체를 다른 데이터 구조에 바인딩하는 것입니다. 이 바인딩은 실제로 객체 위치와 렌더링 정보에 대한 참조 만 있으면됩니다.
레벨 / 청크 / 영역 /지도 / 허브 / 전체 월드 / 공간 인덱스가 제공되는 것에 관계없이 여기에는 객체가 포함되며 좌표 쿼리를 기반으로 객체가 반환되며 간단한 목록 또는 Octree와 같은 것일 수 있습니다. 또한 제 3 자 물리 엔진이 물리 장면으로 구현 한 것에 대한 래퍼 일 수도 있습니다. "카메라 주변에 여분의 영역이있는 카메라 뷰에있는 모든 객체 쿼리"또는 모든 것을 전체 렌더링 할 수있는 간단한 게임과 같은 작업을 수행 할 수 있습니다.
공간 인덱스에는 실제 위치 정보가 포함되어 있지 않아도됩니다. 다른 객체의 위치와 관련하여 트리 구조로 객체를 저장하여 작동합니다. 그것들은 위치에 따라 객체를 신속하게 조회 할 수있는 일종의 손실 캐시 일 수 있습니다. 실제 X, Y, Z 좌표를 복제 할 필요는 없습니다. 당신이 유지하고 싶다면 할 수 있다고 말했다
실제로 게임 오브젝트에는 자체 위치 정보가 포함되어 있지 않아도됩니다. 예를 들어, 레벨에 놓이지 않은 오브젝트에는 x, y, z 좌표가 없어야합니다. 특수 색인에 포함시킬 수 있습니다. 실제 참조를 기준으로 객체의 좌표를 조회해야하는 경우 객체와 장면 그래프를 바인딩해야합니다 (씬 그래프는 좌표를 기준으로 객체를 반환하기위한 것이지만 객체를 기반으로 좌표를 반환하는 속도는 느림). .
레벨에 객체를 추가 할 때. 다음을 수행합니다.
1) 위치 구조를 만듭니다.
class Location {
float x, y, z; // Or a special Coordinates class, or a vec3 or whatever.
SpacialIndex& spacialIndex; // Note this could be the area/level/map/whatever here
};
이는 타사 물리 엔진의 객체에 대한 참조 일 수도 있습니다. 또는 다른 위치 (추적 카메라 또는 부착 된 객체 또는 예)를 참조하여 오프셋 좌표가 될 수 있습니다. 다형성을 사용하면 정적 또는 동적 객체인지에 따라 다를 수 있습니다. 좌표가 업데이트 될 때 공간 인덱스에 대한 참조를 유지함으로써 공간 인덱스도 될 수 있습니다.
동적 메모리 할당이 걱정되면 메모리 풀을 사용하십시오.
2) 객체, 객체의 위치 및 장면 그래프 간의 바인딩 / 링크.
typedef std::pair<Object, Location> SpacialBinding.
3) 바인딩은 적절한 지점에서 레벨 내부의 공간 인덱스에 추가됩니다.
렌더링을 준비 할 때
1) 카메라를 가져옵니다 (위치는 플레이어 캐릭터를 추적하고 렌더러가 실제로 필요한 모든 것을 참조한다는 점을 제외하고는 다른 객체 일뿐입니다).
2) 카메라의 SpacialBinding을 가져옵니다.
3) 바인딩에서 공간 인덱스를 가져옵니다.
4) 카메라에 보이는 물체를 쿼리합니다.
5A) 시각 정보를 처리해야합니다. GPU 등에 텍스처가 업로드되었습니다. 이것은 (레벨로드와 같은) 사전에 가장 잘 수행되지만 런타임에 수행 될 수도 있습니다 (오픈 월드의 경우 청크에 가까울 때로드 할 수 있지만 여전히 미리 수행해야 함).
5B) 선택적으로 캐시 된 렌더 트리를 구축합니다. 깊이 / 재료 정렬을 원하거나 근처에있는 객체를 추적하려는 경우 나중에 볼 수 있습니다. 그렇지 않으면 게임 / 성능 요구 사항에 따라 공간 인덱스를 쿼리 할 수 있습니다.
렌더러에는 Object와 좌표 사이를 연결하는 RenderBinding 객체가 필요할 것입니다.
class RenderBinding {
Object& object;
RenderInformation& renderInfo;
Location& location // This could just be a coordinates class.
}
그런 다음 렌더링 할 때 목록을 통해 실행하십시오.
위의 참조를 사용했지만 스마트 포인터, 원시 포인터, 객체 핸들 등이 될 수 있습니다.
편집하다:
class Game {
weak_ptr<Camera> camera;
Level level1;
void init() {
Camera camera(75.0_deg, 1.025_ratio, 1000_meters);
auto template_player = loadObject("Player.json")
auto player = level1.addObject(move(player), Position(1.0, 2.0, 3.0));
level1.addObject(move(camera), getRelativePosition(player));
auto template_bad_guy = loadObject("BadGuy.json")
level1.addObject(template_bad_guy, {10, 10, 20});
level1.addObject(template_bad_guy, {10, 30, 20});
level1.addObject(move(template_bad_guy), {50, 30, 20});
}
void render() {
camera->getFrustrum();
auto level = camera->getLocation()->getLevel();
auto object = level.getVisible(camera);
for(object : objects) {
render(objects);
}
}
void render(Object& object) {
auto ri = object.getRenderInfo();
renderVBO(ri.getVBO());
}
Object loadObject(string file) {
Object object;
// Load file from disk and set the properties
// Upload mesh data, textures to GPU. Load shaders whatever.
object.setHitPoints(// values from file);
object.setRenderInfo(// data from 3D api);
}
}
class Level {
Octree octree;
vector<ObjectPtr> objects;
// NOTE: If your level is mesh based there might also be a BSP here. Or a hightmap for an openworld
// There could also be a physics scene here.
ObjectPtr addObject(Object&& object, Position& pos) {
Location location(pos, level, object);
objects.emplace_back(object);
object->setLocation(location)
return octree.addObject(location);
}
vector<Object> getVisible(Camera& camera) {
auto f = camera.getFtrustrum();
return octree.getObjectsInFrustrum(f);
}
void updatePosition(LocationPtr l) {
octree->updatePosition(l);
}
}
class Octree {
OctreeNode root_node;
ObjectPtr add(Location&& object) {
return root_node.add(location);
}
vector<ObjectPtr> getObjectsInRadius(const vec3& position, const float& radius) { // pass to root_node };
vector<ObjectPtr> getObjectsinFrustrum(const FrustrumShape frustrum;) {//...}
void updatePosition(LocationPtr* l) {
// Walk up from l.octree_node until you reach the new place
// Check if objects are colliding
// l.object.CollidedWith(other)
}
}
class Object {
Location location;
RenderInfo render_info;
Properties object_props;
Position getPosition() { return getLocation().position; }
Location getLocation() { return location; }
void collidedWith(ObjectPtr other) {
// if other.isPickup() && object.needs(other.pickupType()) pick it up, play sound whatever
}
}
class Location {
Position position;
LevelPtr level;
ObjectPtr object;
OctreeNote octree_node;
setPosition(Position position) {
position = position;
level.updatePosition(this);
}
}
class Position {
vec3 coordinates;
vec3 rotation;
}
class RenderInfo {
AnimationState anim;
}
class RenderInfo_OpenGL : public RenderInfo {
GLuint vbo_object;
GLuint texture_object;
GLuint shader_object;
}
class Camera: public Object {
Degrees fov;
Ratio aspect;
Meters draw_distance;
Frustrum getFrustrum() {
// Use above to make a skewed frustum box
}
}
서로를 '인식'하는 것. 충돌 감지입니다. 아마도 Octree에서 구현 될 것입니다. 기본 객체에 콜백을 제공해야합니다. 이 물건은 Bullet과 같은 적절한 물리 엔진에 의해 가장 잘 처리됩니다. 이 경우 Octree를 PhysicsScene 및 Position으로 CollisionMesh.getPosition ()과 같은 링크로 바꿉니다.