OpenGL 3.x です。技術面で遅れをとりたくないからです。
まず第一に、はい、私はそれがたくさんあることを知っています. 機能が問題ないことはほぼ確実です。vec3 transform(vec3)
他に何もないとしても、私がここに来た問題が含まれていないことはわかっています。
私が問題を抱えているコードのビットは、関数にあります(またはあるべきです)vec3 project(vec3)
。たとえば、ボックスを直接見ている場合は、問題ないように見えます。ボックスが画面の側面に近づくようにカメラを少し回転させると (周辺視野)、ハッピー ボックスの開始点が長方形になります。それは私が入れているゲームで私が一緒に暮らすことができるものですが、それは面倒です.
投影の背後にある基本的な理論は次のとおりです。ポイント (x、y、z) があり、それと原点 (カメラがある場所) の間の角度を見つけ、nearz
離れた平面に投影します。角度を見つけることは と の問題angleX = atan(x/z)
ですangleY = atan(y/z)
。これらの 2 つの角度を使用して、 を実行して近平面に投影しますpoint = tan(angle) * nearz
。edgeY = tan(fovy) * nearz
次に、とで画面の外側の尾根を見つけますedgeX = tan(fovy * aspect) * nearz
。を使用してスクリーンポイントを見つけるscreen = point/edge
私が持っていた基本的な最適化として、これを修正するために削除したのはscreen = angle/fov
私の射影関数の理論に何か問題がありますか? 実装は次のとおりです。
#version 330
uniform vec3 model_location = vec3(0.0, 0.0, 0.0);
uniform vec3 model_rotation = vec3(0.0, 0.0, 0.0);
uniform vec3 model_scale = vec3(1.0, 1.0, 1.0);
uniform vec3 camera_location = vec3(0.0, 0.0, 0.0);
uniform vec3 camera_rotation = vec3(0.0, 0.0, 0.0);
uniform vec3 camera_scale = vec3(1.0, 1.0, 1.0);
uniform float fovy = 60.0;
uniform float nearz = 0.01;
uniform float farz = 1000.0;
uniform float aspect = 1.0;
vec3 transform(vec3 point)
{
vec3 translate = model_location - camera_location;
vec3 rotate = radians(model_rotation);
vec3 scale = model_scale / camera_scale;
vec3 s = vec3(sin(rotate.x), sin(rotate.y), sin(rotate.z));
vec3 c = vec3(cos(rotate.x), cos(rotate.y), cos(rotate.z));
float sy_cz = s.y * c.z;
float sy_sz = s.y * s.z;
float cx_sz = c.x * s.z;
vec3 result;
result.x = ( point.x * ( ( c.y * c.z ) * scale.x ) ) + ( point.y * ( ( ( -cx_sz ) + ( s.x * sy_cz ) ) * scale.y ) ) + ( point.z * ( ( ( -s.x * s.z ) + ( c.x * sy_cz ) ) * scale.z ) ) + translate.x;
result.y = ( point.x * ( ( c.y * s.z ) * scale.y ) ) + ( point.y * ( ( ( c.x * c.z ) + ( s.x * sy_sz ) ) * scale.y ) ) + ( point.z * ( ( ( -s.x * c.z ) + ( c.x * sy_sz ) ) * scale.z ) ) + translate.y;
result.z = ( point.x * ( ( -s.y ) * scale.x ) ) + ( point.y * ( ( s.x * c.y ) * scale.y ) ) + ( point.z * ( ( c.x * c.y ) * scale.z ) ) + translate.z;
return result;
}
vec4 project(vec3 point)
{
vec4 result = vec4(0.0);
vec3 rotation = radians(camera_rotation);
result.x = ( atan(point.x/point.z) - rotation.y );
result.y = ( atan(point.y/point.z) - rotation.x );
result.z = point.z/(farz - nearz);
result.w = 1.0;
result.x = tan(result.x) * nearz;
result.y = tan(result.y) * nearz;
vec2 bounds = vec2( tan(fovy * aspect) * nearz,
tan(fovy) * nearz );
result.x = result.x / bounds.x;
result.y = result.y / bounds.y;
if (camera_rotation.z == 0)
return result;
float dist = sqrt( (result.x*result.x) + (result.y*result.y) );
float theta = atan(result.y/result.x) + rotation.z;
result.x = sin(theta) * dist;
result.y = cos(theta) * dist;
return result;
}
layout(location = 0) in vec3 vertex_position;
layout(location = 1) in vec2 texCoord;
out vec2 uvCoord;
void main()
{
uvCoord = texCoord;
vec4 pos = project( transform(vertex_position) );
if (pos.z < 0.0)
return;
gl_Position = pos;
}
予想されるいくつかの質問に答えるには:
Q: なぜ GLM/some-other-mathematics-lib を使わないのですか?
A:
- ちょっと前にやってみた。私の「ハローワールド!」三角形が画面中央に引っかかっていました。変換行列を使用しても、前に戻したり、スケーリングしたり、何もしませんでした。
-自分自身のために物事を理解する方法を学ぶことが重要だから. これを行うということは、すべてが手に負えなくなった場合に頼りになる何かを持ちながら、このようなことに取り組む方法を学ぶことを意味します. (この愚か者の正当化があります。)
Q: なぜ行列を使用しないのですか?
A:
-彼らも私を嫌っています。
-私は新しい方法でそれをやっています.マトリックスを使用した場合、自分でそれを理解するのではなく、すべてのチュートリアルがそれを行うと言っているとおりにそれを行うことになります.
試したソース:
http://ogldev.atspace.co.uk/index.html
http://www.swiftless.com/opengltuts/opengl4tuts.html
ページの「OpenGL シェーディング言語第 3 版」、「OpenGL 固定機能のエミュレート」から GLSL シェーダ (頂点とフラグ) を文字ごとにコピーしました。288-293
それぞれを何度も試し、それぞれをいじくり回して狂気に陥りました。戦争ゲームをプログラムしようとして、ワイヤーフレームのボックスを手に入れて、平和のシンボルに投影しました。
編集:
問題は、datenwolf が指摘した極座標の使用であることが判明しました。あまり進んでいない数学を使用した射影のためのより良い方程式は次のc = zNear * (p.x/p.y)
とおりです。その結果、同じ角度を使用します。
投影される点に X と Y が与えられ、それらの前部分三角形の辺にそれぞれ A と C のラベルが付けられていると仮定します。atan(Y/X) = angle
等式のandを取得できます。それatan(C/A) = angle
から
、A は近くの平面までの距離で終わります。C は Y 方向のスクリーン座標です。atan(Y/X) = atan(C/A)
Y/X = C/A
C = A * (Y/X)