2011-12-22 31 views
5

Tôi đang viết một bản sao của Wolfenstein 3D chỉ sử dụng lõi OpenGL 3.3 cho trường đại học và tôi đã gặp phải một chút vấn đề với sprites. về khoảng cách. Từ những gì tôi có thể nói, các phiên bản trước của OGL thực tế sẽ làm điều này cho bạn, nhưng chức năng đó đã bị xóa và tất cả những nỗ lực của tôi để thực hiện lại nó đã dẫn đến thất bại hoàn toàn.Thay đổi kích thước điểm ảnh sprites dựa trên khoảng cách từ máy ảnh

Triển khai hiện tại của tôi có thể thực hiện được ở khoảng cách, không quá tồi tàn ở tầm trung và bizzare ở cự ly gần.

Vấn đề chính (tôi nghĩ) là tôi không hiểu về toán học tôi đang sử dụng.
Kích thước mục tiêu của sprite là lớn hơn một chút so với khung nhìn, vì vậy nó nên 'đi ra khỏi hình ảnh' khi bạn nhận được quyền lên đến nó, nhưng nó không. Nó trở nên nhỏ hơn và điều đó khiến tôi khó hiểu.
Tôi đã ghi lại một video nhỏ về điều này, trong trường hợp các từ không đủ. (Mine là ở bên phải)

Expected Result Actual Result

bất cứ ai có thể trực tiếp tôi để nơi tôi sẽ sai, và giải thích lý do tại sao?

Code:
C++

// setup 
glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT); 
glEnable(GL_PROGRAM_POINT_SIZE); 

// Drawing 
glUseProgram(StaticsProg); 
glBindVertexArray(statixVAO); 
glUniformMatrix4fv(uStatixMVP, 1, GL_FALSE, glm::value_ptr(MVP)); 
glDrawArrays(GL_POINTS, 0, iNumSprites); 

Vertex Shader

#version 330 core 

layout(location = 0) in vec2 pos; 
layout(location = 1) in int spriteNum_; 

flat out int spriteNum; 

uniform mat4 MVP; 

const float constAtten = 0.9; 
const float linearAtten = 0.6; 
const float quadAtten = 0.001; 

void main() { 
    spriteNum = spriteNum_; 
    gl_Position = MVP * vec4(pos.x + 1, pos.y, 0.5, 1); // Note: I have fiddled the MVP so that z is height rather than depth, since this is how I learned my vectors. 
    float dist = distance(gl_Position, vec4(0,0,0,1)); 
    float attn = constAtten/((1 + linearAtten * dist) * (1 + quadAtten * dist * dist)); 
    gl_PointSize = 768.0 * attn; 
} 

Fragment Shader

#version 330 core 

flat in int spriteNum; 

out vec4 color; 

uniform sampler2DArray Sprites; 

void main() { 
    color = texture(Sprites, vec3(gl_PointCoord.s, gl_PointCoord.t, spriteNum)); 
    if (color.a < 0.2) 
     discard; 
} 
+0

Tại sao bạn sử dụng 'pos.x + 1'? –

+0

Tôi nghĩ rằng đó là bởi vì anh ta đặt vị trí trung tâm ma sát xuống bên trái, nhưng anh ta thực sự muốn điểm neo ở trung tâm trên cùng. –

+0

Tôi muốn điểm gắn kết nằm ở trung tâm của cạnh dưới, nhưng vì một loạt các vấn đề liên kết mà tôi không có xung quanh để phân loại, tôi phải thay đổi rất nhiều thứ xung quanh một cách kỳ lạ. –

Trả lời

11

Trước hết, tôi thực sự không hiểu tại sao bạn sử dụng pos.x + 1.

Tiếp theo, như Nathan đã nói, bạn không nên sử dụng điểm nhấn không gian, mà là điểm không gian con mắt. Điều này có nghĩa là bạn chỉ sử dụng điểm chuyển đổi modelview (không có phép chiếu) để tính khoảng cách.

uniform mat4 MV;  //modelview matrix 

vec3 eyePos = MV * vec4(pos.x, pos.y, 0.5, 1); 

Ngoài ra, tôi không hoàn toàn hiểu tính toán suy giảm của bạn. Hiện tại giá trị constAtten cao hơn đồng nghĩa với việc ít bị suy giảm hơn.Tại sao bạn không chỉ cần sử dụng các mô hình mà các thông số điểm NỮA OpenGL đã sử dụng:

float dist = length(eyePos); //since the distance to (0,0,0) is just the length 
float attn = inversesqrt(constAtten + linearAtten*dist + quadAtten*dist*dist); 

EDIT: Nhưng nói chung tôi nghĩ rằng mô hình suy giảm này không phải là một cách tốt, bởi vì thường bạn chỉ muốn sprite để giữ kích thước không gian đối tượng của nó, mà bạn có khá fiddle với các yếu tố suy giảm để đạt được mà tôi nghĩ.

Cách tốt hơn là đầu vào kích thước không gian đối tượng của nó và chỉ cần tính toán kích thước màn hình không gian bằng pixel (đó là những gì gl_PointSize thực sự là) trên cơ sở đó sử dụng giao diện hiện tại và thiết lập chiếu:

uniform mat4 MV;    //modelview matrix 
uniform mat4 P;     //projection matrix 
uniform float spriteWidth;  //object space width of sprite (maybe an per-vertex in) 
uniform float screenWidth;  //screen width in pixels 

vec4 eyePos = MV * vec4(pos.x, pos.y, 0.5, 1); 
vec4 projCorner = P * vec4(0.5*spriteWidth, 0.5*spriteWidth, eyePos.z, eyePos.w); 
gl_PointSize = screenWidth * projCorner.x/projCorner.w; 
gl_Position = P * eyePos; 

này cách các sprite luôn luôn được kích thước nó sẽ có khi kết xuất như một quad kết cấu với chiều rộng spriteWidth.

CHỈNH SỬA: Tất nhiên, bạn cũng nên ghi nhớ các giới hạn của điểm họa tiết. Một điểm sprite được cắt bớt dựa trên vị trí trung tâm của nó. Điều này có nghĩa là khi trung tâm của nó di chuyển ra khỏi màn hình, toàn bộ sprite biến mất. Với các sprites lớn (như trong trường hợp của bạn, tôi nghĩ) điều này thực sự có thể là một vấn đề.

Vì vậy, tôi muốn đề xuất bạn sử dụng các điểm tứ kết cấu đơn giản. Bằng cách này, bạn phá vỡ toàn bộ vấn đề suy giảm này, vì các quad chỉ được biến đổi giống như mọi đối tượng 3D khác. Bạn chỉ cần thực hiện xoay vòng đối với người xem, có thể được thực hiện trên CPU hoặc trong trình đổ bóng đỉnh.

+0

Đoạn mã thứ hai của bạn gây ra [this] (http://i.imgur.com/EvTwW.png), và tôi không hoàn toàn chắc chắn nó đang làm gì. Bạn có thể giải thích thêm được không? Tôi cũng sẽ nhìn vào các quad. –

+0

@Lexi Ý của bạn là gì, chỉnh sửa đầu tiên? –

+0

Vâng, người có projCorner. –

1

Tôi không nghĩ rằng bạn muốn tính toán khoảng cách trong trình đổ bóng đỉnh của mình trên được chiếu vị trí. Thay vào đó, chỉ cần tính toán vị trí liên quan đến chế độ xem của bạn, tức là sử dụng ma trận chế độ xem mô hình thay vì chế độ xem mô hình-xem.

Hãy suy nghĩ về nó theo cách này - trong không gian dự kiến, như một đối tượng được gần gũi hơn với bạn, khoảng cách của nó theo hướng ngang và dọc trở nên phóng đại. Bạn có thể thấy điều này theo cách các đèn di chuyển ra khỏi trung tâm về phía trên cùng của màn hình khi bạn tiếp cận chúng. Sự phóng đại của những kích thước đó sẽ làm cho khoảng cách trở nên lớn hơn khi bạn thực sự gần gũi, đó là lý do tại sao bạn nhìn thấy vật thể co lại.

5

Dựa trên Christian Rau's answer (chỉnh sửa cuối cùng), tôi thực hiện một Shader hình học mà xây dựng một biển quảng cáo ở ViewSpace, mà dường như để giải quyết tất cả các vấn đề của tôi:

Expected Result Actual Result

Sau đây là các shaders: (Lưu ý mà tôi đã khắc phục sự cố liên kết mà yêu cầu đổ bóng ban đầu để thêm từ 1 tới x)

Vertex Shader

#version 330 core 

layout (location = 0) in vec4 gridPos; 
layout (location = 1) in int spriteNum_in; 

flat out int spriteNum; 

// simple pass-thru to the geometry generator 
void main() { 
    gl_Position = gridPos; 
    spriteNum = spriteNum_in; 
} 

Geometry Shader

#version 330 core 

layout (points) in; 
layout (triangle_strip, max_vertices = 4) out; 

flat in int spriteNum[]; 

smooth out vec3 stp; 

uniform mat4 Projection; 
uniform mat4 View; 

void main() { 
    // Put us into screen space. 
    vec4 pos = View * gl_in[0].gl_Position; 

    int snum = spriteNum[0]; 

    // Bottom left corner 
    gl_Position = pos; 
    gl_Position.x += 0.5; 
    gl_Position = Projection * gl_Position; 
    stp = vec3(0, 0, snum); 
    EmitVertex(); 

    // Top left corner 
    gl_Position = pos; 
    gl_Position.x += 0.5; 
    gl_Position.y += 1; 
    gl_Position = Projection * gl_Position; 
    stp = vec3(0, 1, snum); 
    EmitVertex(); 

    // Bottom right corner 
    gl_Position = pos; 
    gl_Position.x -= 0.5; 
    gl_Position = Projection * gl_Position; 
    stp = vec3(1, 0, snum); 
    EmitVertex(); 

    // Top right corner 
    gl_Position = pos; 
    gl_Position.x -= 0.5; 
    gl_Position.y += 1; 
    gl_Position = Projection * gl_Position; 
    stp = vec3(1, 1, snum); 
    EmitVertex(); 

    EndPrimitive(); 
} 

Fragment Shader

#version 330 core 

smooth in vec3 stp; 

out vec4 colour; 

uniform sampler2DArray Sprites; 

void main() { 
    colour = texture(Sprites, stp); 
    if (colour.a < 0.2) 
     discard; 
} 
+2

Vì vậy, câu trả lời của Christian Rau là những gì đã đưa bạn đến nơi bạn đang ở, nhưng bạn chấp nhận câu trả lời của riêng bạn? Wow, đó là vô cùng suy nghĩ sau khi nỗ lực ông đưa vào. Cách để đưa mọi người cho các cấp. –

+0

@NickWiggill Tôi đã không thực sự nghĩ về điều đó một cách trung thực. Tôi đã thực hiện và chấp nhận câu trả lời của tôi bởi vì tôi nghĩ rằng nó sẽ hữu ích hơn cho bất cứ ai khác với vấn đề của tôi. –

+0

+1 trên câu trả lời của bạn để bạn xem xét trong việc gán lại câu trả lời được chấp nhận. Của bạn có lẽ sẽ kết thúc với nhiều phiếu bầu anyway. –

0

Ít nhất trong OpenGL ES 2.0, có một giới hạn kích thước tối đa trên gl_PointSize áp đặt bởi việc thực hiện OpenGL. Bạn có thể truy vấn kích thước bằng ALIASED_POINT_SIZE_RANGE.

Các vấn đề liên quan