房间内的光源意外动作 [英] Light source inside a room acting unexpectedly

查看:103
本文介绍了房间内的光源意外动作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经编写了多个Android应用程序,但这是我第一次体验3D编程.

I've written several Android apps, but this is my first experience with 3D programming.

我创建了一个房间(4墙,天花板和地板),里面有几个对象,能够像走着一样在周围移动相机.我已经用各种图像对所有表面进行了纹理处理,并且一切都按预期进行.

I've created a room (4 walls, ceiling and floor) with a couple objects inside and am able to move the camera around it as if walking. I've textured all surfaces with various images and everything was working as expected.

就上下文而言,房间的宽度为14个单位,深度为16个单位(以原点为中心),高度为3个单位(原点上方1个单位,下方2个单位).房间中间有两个物体,一个立方体和一个倒置的金字塔.

For context, the room is 14 units wide and 16 units deep (centered at origin), 3 units high (1 above origin and 2 below). There are 2 objects in the middle of the room, a cube and an inverted pyramid on top of it.

然后我去添加一个光源来遮盖立方体和金字塔.我已经阅读并跟踪了NeHe的几个端口,因此我将本课中有关照明的内容用于我的新代码.

Then I went to add a light source to shade the cube and pyramid. I had read through and followed a couple of NeHe's ports, so I took what I had working in the lesson on lighting and applied it to my new code.

gl.glEnable(GL10.GL_LIGHTING);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, new float[] { 0.1f, 0.1f, 0.1f, 1f }, 0);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, new float[] { 1f, 1f, 1f, 1f }, 0);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, new float[] { -4f, 0.9f, 6f, 1f }, 0);
gl.glEnable(GL10.GL_LIGHT0);

结果是立方体和金字塔未​​着色.它们在与光相对的侧面上看起来与在与光相对的侧面上看起来相同.当摄像机直接指向远离光源的位置时,房间的外观与添加照明代码之前的样子相同.当我旋转相机以面对光源时,当相机直接面对光源时,整个房间(包括物体)会变暗直到完全变黑.

The result is that the cube and pyramid are not shaded. They look the same on sides opposing the light as they do on the sides facing it. When the camera is pointed directly away from the light source the room looks as it did before I added the lighting code. As I rotate the camera to face the light source the entire room (including objects) becomes darker until completely black when the camera is directly facing the source.

这是怎么回事?我阅读了许多有关照明及其工作原理的文章,但是我没有看到任何东西可以说明为什么这种照明不能照亮房间的所有侧面,而立方体和金字塔是根据照明位置进行着色的.光线是否在房间内,是否存在某些预期的行为?因为我是新来的,我只是错过了一些简单的事情吗?

What is going on here? I read many articles on lighting and how it works, but I have seen nothing to indicate why this wouldn't light up all sides of the room, with the cube and pyramid shaded based on the light position. Is there some expected behavior of the light because it is "inside" the room? Am I just missing something easy because I'm new?

推荐答案

3D世界中的每个对象都有一个

Every object in your 3D world has a normal, where it helps OpenGL to determine how much light an object need to reflect. You've probably forgot to specify the normals for your surfaces. Without specifying them, OpenGL will light all objects in your world in the same way.

要获得3D曲面的法线,您至少需要三个顶点,这意味着它至少是一个三角形.

In order to get a surface's normal in 3D you need at least three vertices, which means it at least is a triangle.

示例内容:

要计算表面的法线,您需要两个向量.由于您在3D空间中有三个顶点,这意味着这些采样点可能包含一个三角形:

In order to calculate a surface's normal you need two vectors. Since you have three vertices in 3D space that means that these sample points could contain a triangle:

// Top triangle, three points in 3D space.
vertices = new float[] {
   -1.0f, 1.0f, -1.0f,
   1.0f, 1.0f, -1.0f,
   0.0f, 1.0f, -1.0f,
}

鉴于这三个点,您现在可以通过以下方式定义两个向量:

Given these three points, you can now define two vectors by the following:

// Simple vector class, created by you.
Vector3f vector1 = new Vector3f();
Vector3f vector2 = new Vector3f();

vector1.x = vertices[0] - vertices[3];
vector1.y = vertices[1] - vertices[4];
vector1.z = vertices[2] - vertices[5];

vector2.x = vertices[3] - vertices[6];
vector2.y = vertices[4] - vertices[7];
vector2.z = vertices[5] - vertices[8];

现在,当您拥有两个向量时,最终可以使用叉积.简而言之,叉积是一种运算,它产生一个新矢量,该矢量包含一个与输入矢量垂直的角度.这是我们需要的 normal .

Now when you have two vectors, you can finally get the surface's normal by using the Cross Product. Shortly, the cross product is an operation which results in a new vector containing an angle that is perpendicular to the input vectors. This is the normal that we need.

要在代码中获得叉积,您必须编写自己的计算乘积的方法.理论上,您可以根据以下公式计算叉积:

To get the cross product in your code you have to write your own method that calculates it. In theory you calculate the cross product given this formula:

A X B =(A.y * B.z-A.z * B.y,A.z * B.x-A.x * B.z,A.x * B.y-A.y * B.x)

A X B = (A.y * B.z - A.z * B.y, A.z * B.x - A.x * B.z, A.x * B.y - A.y * B.x)

在代码中(通过使用上面的向量):

In code (by using the vectors above):

public Vector3f crossProduct(Vector3f vector1, Vector3f vector2) {
    Vector3f normalVector = new Vector3f();

    // Cross product. The normalVector contains the normal for the
    // surface, which is perpendicular both to vector1 and vector2.
    normalVector.x = vector1.y * vector2.z - vector1.z * vector2.y;
    normalVector.y = vector1.z * vector2.x - vector1.x * vector2.z;
    normalVector.z = vector1.x * vector2.y - vector1.y * vector2.x;

    return normalVector;
}

在发表进一步评论之前;您可以在数组中指定法线,并在需要时将其放入OpenGL中,但是如果您深入研究该主题,代码将更加灵活.

Before any further comments; you can specify your normals in an array and just put them into OpenGL when needed, but your understanding of this topic will be much better if you dig into it and your code will be much more flexible.

因此,现在我们有了一个法线,您可以遍历该法线,将向量值分配给您的法线数组(如NeHe的端口,但要动态地),并将OpenGL设置为使用GL_NORMAL_ARRAY以便使OpenGL反射光.正确的对象:

So now we have a normal which you can loop through, assign the vector values to your normal array (like NeHe's ports, but dynamically) and set up OpenGL to use GL_NORMAL_ARRAY in order to get OpenGL to reflect the light on the object correctly:

gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);

// I'm assuming you know how to put it into a FloatBuffer.
gl.glNormalPointer(GL10.GL_FLOAT, 0, mNormalsBuffer);

// Draw your surface...

另一条最后评论;如果您使用其他顶点值(例如5.0f,10.0f或更大),则可能要规范化crossProduct()方法返回的向量,以获得一些性能.否则,OpenGL必须计算新向量以获得单位向量,这可能是性能问题.

Another last comment; if you're using other vertices values (like 5.0f, 10.0f or bigger) you might wanna normalize the vector that returns from the crossProduct() method in order to gain some performance. Otherwise OpenGL must calculate the new vector to get the unit vector and that might be a performance issue.

此外,您对GL_POSITIONnew float[] {-4f, 0.9f, 6f, 1f}不太正确.当第四个值设置为1.0f时,则意味着无论前三个值是什么,灯光位置均为0, 0, 0.为了为您的灯光位置指定矢量,请将第四个值更改为0.0f.

Also, your new float[] {-4f, 0.9f, 6f, 1f} for GL_POSITION is not quite correct. When the fourth value is set to 1.0f it means that the light position is 0, 0, 0, no matter what the first three values are. In order to specify a vector for your light position, change the fourth value to 0.0f.

这篇关于房间内的光源意外动作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆