[英]How do I draw ellipse in opengl with mvp
如何绘制圆/椭圆并使用 Model-View-Projection 对其进行转换。
我用glDrawElements(GL_TRIANGLES, ...)
在一个矩形中画了一个椭圆。
我做了一个着色器,它可以工作,但是如何转换它呢?
顶点着色器
#version 330 core
layout (location = 0) in vec2 position;
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
}
片段着色器
#version 400 core
uniform mat4 u_mvp;
uniform vec2 u_resolution;
out vec4 color;
float pow2(float x) { return x * x; }
void main()
{
vec2 d = (gl_FragCoord.xy / u_resolution.xy) * 2 - vec2(1.0);
vec4 pos = vec4(d, 0.0, 0.0);
vec4 center = vec4(0.0);
float r = distance(pos, center);
r = step(0.5, r);
color = vec4(0.7f, 0.8f, 0.1f, 1.0f - r);
}
如何添加 MVP 支持?
有不同的选择,以实现您想要的。 其中一个是创建一个与射线和球体相交的 function。
下面的算法取自Peter Shirley 的书Ray Tracing in One Weekend 。
射线origin
点和direction
定义。 球体由center
和radius
定义:
float hit_sphere(vec3 origin, vec3 direction, vec3 center, float radius)
{
vec3 oc = origin - center;
float a = dot(direction, direction);
float b = 2.0 * dot(oc, direction);
float c = dot(oc, oc) - radius*radius;
float discriminant = b*b - 4*a*c;
if (discriminant > 0.0)
{
float temp = (-b - sqrt(discriminant)) / (2*a);
if (temp > 0.0)
return 1.0;
temp = (-b + sqrt(discriminant)) / (2*a);
if (temp > 0.0)
return 1.0;
}
return 0.0;
}
计算射线上的 2 个点。 xy 坐标xy = gl_FragCoord.xy / u_resolution.xy * 2.0 - 1.0
的标准化设备空间中的每个点都在同一条射线上。 vec4(xy, -1.0, 1.0)
在近平面上, vec4(xy, 1.0, 1.0)
在远平面上。 通过inverse
model 视图投影矩阵 ( u_mvp
) 变换该点,并将xyz
分量除以w
分量,以在笛卡尔坐标系的 model 空间中获得一条射线。
大小算法计算射线上的 2 个点,这适用于透视投影和正交投影。
vec4 pn = inverse(u_mvp) * vec4(xy, -1.0, 1.0);
vec4 pf = inverse(u_mvp) * vec4(xy, 1.0, 1.0);
vec3 orig = pn.xyz/pn.w;
vec3 dir = pf.xyz/pf.w - orig;
使用射线与 model 空间中的球体相交:
vec3 center = vec3(0.0);
float radius = 1.0;
float r = hit_sphere(orig, dir, center, radius);
我已经用视图矩阵glm::translate(glm::mat4(1), glm::vec3(0, 0, -3))
和投影矩阵glm::perspective(glm::radians(90), aspect, 0.1, 10.0)
片段着色器:
#version 330 core
out vec4 frag_color;
uniform mat4 u_mvp;
uniform vec2 u_resolution;
float hit_sphere(vec3 origin, vec3 direction, vec3 center, float radius)
{
vec3 oc = origin - center;
float a = dot(direction, direction);
float b = 2.0 * dot(oc, direction);
float c = dot(oc, oc) - radius*radius;
float discriminant = b*b - 4*a*c;
if (discriminant > 0.0)
{
float temp = (-b - sqrt(discriminant)) / (2*a);
if (temp > 0.0)
return 1.0;
temp = (-b + sqrt(discriminant)) / (2*a);
if (temp > 0.0)
return 1.0;
}
return 0.0;
}
void main()
{
vec2 xy = gl_FragCoord.xy / u_resolution.xy * 2.0 - 1.0;
vec4 pn = inverse(u_mvp) * vec4(xy, -1.0, 1.0);
vec4 pf = inverse(u_mvp) * vec4(xy, 1.0, 1.0);
vec3 orig = pn.xyz/pn.w;
vec3 dir = pf.xyz/pf.w - orig;
vec3 center = vec3(0.0);
float radius = 1.0;
float r = hit_sphere(orig, dir, center, radius);
vec4 backcolor = vec4(0.2, 0.3, 0.3, 1.0);
vec4 color = vec4(0.7, 0.8, 0.1, 1.0);
frag_color = mix(backcolor, color, r);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.