如何使用片段着色器在OpenGL ES中绘制球体错觉?

时间:2013-04-08 10:18:49

标签: opengl-es shader

我正在使用这个简单的功能在面向相机的3D空间中绘制四边形。现在,我想使用片段着色器来绘制内部球体的错觉。但是,问题是我是OpenGL ES的新手,所以我不知道怎么做?

void draw_sphere(view_t view) {

    set_gl_options(COURSE);

    glPushMatrix();
    {
        glTranslatef(view.plyr_pos.x, view.plyr_pos.y, view.plyr_pos.z - 1.9);
#ifdef __APPLE__
#undef  glEnableClientState
#undef  glDisableClientState
#undef  glVertexPointer
#undef  glTexCoordPointer
#undef  glDrawArrays

        static const GLfloat vertices []=
        {
            0, 0, 0,
            1, 0, 0,
            1, 1, 0,
            0, 1, 0,
            0, 0, 0,
            1, 1, 0
        };

        glEnableClientState(GL_VERTEX_ARRAY);
        glVertexPointer(3, GL_FLOAT, 0, vertices);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
        glDisableClientState(GL_VERTEX_ARRAY);
#else
#endif
    }
    glPopMatrix();
}

更确切地说,我想实现这个目标: Enhancing Molecules using OpenGL ES 2.0

1 个答案:

答案 0 :(得分:6)

您可能需要做很多事情来实现这一点......在您发布的最后一张图片上绘制的球体是使用光线和光泽和颜色的结果。通常,您需要一个可以处理所有这些并且通常可以用于任何形状的着色器。

这种特殊情况(也可以用数学方式呈现的其他一些情况)可以使用单个四边形绘制,甚至不需要将正常坐标推送到程序。您需要做的是在片段着色器中创建法线:如果您收到向量sphereCenterfragmentPosition和浮动sphereRadius,则sphereNormal是一个向量,例如

sphereNormal = (fragmentPosition-sphereCenter)/radius; //taking into account all have .z = .0
sphereNormal.z = -sqrt(1.0 - length(sphereNormal)); //only if(length(spherePosition) < sphereRadius)

和实球位置:

spherePosition = sphereCenter + sphereNormal*sphereRadius;

现在你需要做的就是添加你的灯光..静态与否最常见的是使用一些环境因素,线性和方形距离因子,闪耀因子:

color = ambient*materialColor; //apply ambient

vector fragmentToLight = lightPosition-spherePosition;
float lightDistance = length(fragmentToLight);
fragmentToLight = normalize(fragmentToLight); //can also just divide with light distance
float dotFactor = dot(sphereNormal, fragmentToLight); //dot factor is used to take int account the angle between light and surface normal
if(dotFactor > .0) {
   color += (materialColor*dotFactor)/(1.0 + lightDistance*linearFactor + lightDistance*lightDistance*squareFactor); //apply dot factor and distance factors (in many cases the distance factors are 0)
}

vector shineVector = (sphereNormal*(2.0*dotFactor)) - fragmentToLight; //this is a vector that is mirrored through the normal, it is a reflection vector
float shineFactor = dot(shineVector, normalize(cameraPosition-spherePosition)); //factor represents how strong is the light reflection towards the viewer
if(shineFactor > .0) {
   color += materialColor*(shineFactor*shineFactor * shine); //or some other power then 2 (shineFactor*shineFactor)
}

这种在片段着色器中创建灯光的模式是其中之一。如果您不喜欢它或者您无法使其正常工作,我建议您在网上找到另一个,否则我希望您能理解它并能够使用它。

相关问题