gpt4 book ai didi

android - OpenGL ES 2.0 的漫反射着色器 : Light changes with camera movement (Vuforia on Android)

转载 作者:行者123 更新时间:2023-12-01 03:43:12 25 4
gpt4 key购买 nike

作为起点,我使用了名为 MultiTargets 的 Vuforia(版本 4)示例,它跟踪摄像机源中的 3d 物理“立方体”,并沿立方体边缘使用黄色网格线对其进行扩充。
我想要实现的是通过设置我自己的光照位置来移除纹理并在立方体面上使用漫反射光照。

我想在原生 Android 上执行此操作,我不想使用 Unity。

这是几天的工作和学习的艰难旅程。这是我第一次使用任何类型的 OpenGL,而 OpenGL ES 2.0 对初学者来说并不容易。

所以我有一个位于立方体顶面上方的光源。我发现如果我在模型空间中计算朗伯因子,我可以得到正确的漫反射效果,无论我的相机如何,一切都保持在原位,只有顶面有任何光线。

但是当我开始使用眼睛空间时,它变得很奇怪,光线似乎跟着我的相机四处走动。其他面变亮,不仅是顶面。我不明白为什么会这样。为了测试,我通过仅使用到光源的距离在 fragment 着色器中渲染像素亮度来确保灯光位置符合预期。因此,我对我的“lightDirectionEyespace”的正确性相当有信心,我唯一的解释是法线一定是错误的。但我认为我遵循了正确创建法线矩阵的解释......

请帮忙!

那么当然还有一个问题,这些漫反射计算是否应该在眼睛空间中执行?如果我只是在模型空间中这样做会有什么缺点吗?我怀疑当我以后使用更多模型和灯光并添加镜面反射和透明度时,它可能不再起作用,即使我还不明白为什么。

我的 renderFrame 方法:(一些变量名仍然包含“bottle”,这是我在获得正确的立方体后接下来要点亮的对象)

private void renderFrame()
{
ShaderFactory.checkGLError("Check gl errors prior render Frame");

// Clear color and depth buffer
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

// Get the state from Vuforia and mark the beginning of a rendering section
final State state=Renderer.getInstance().begin();

// Explicitly render the Video Background
Renderer.getInstance().drawVideoBackground();

GLES20.glEnable(GLES20.GL_DEPTH_TEST);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);

// Did we find any trackables this frame?
if(0 != state.getNumTrackableResults())
{
// Get the trackable:
TrackableResult result=null;
final int numResults=state.getNumTrackableResults();

// Browse results searching for the MultiTarget
for(int j=0; j < numResults; j++)
{
result=state.getTrackableResult(j);
if(result.isOfType(MultiTargetResult.getClassType()))
break;

result=null;
}

// If it was not found exit
if(null == result)
{
// Clean up and leave
GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);

Renderer.getInstance().end();
return;
}

final Matrix44F modelViewMatrix_Vuforia=Tool.convertPose2GLMatrix(result.getPose());
final float[] modelViewMatrix=modelViewMatrix_Vuforia.getData();

final float[] modelViewProjection=new float[16];
Matrix.scaleM(modelViewMatrix, 0, CUBE_SCALE_X, CUBE_SCALE_Y, CUBE_SCALE_Z);
Matrix.multiplyMM(modelViewProjection, 0, vuforiaAppSession
.getProjectionMatrix().getData(), 0, modelViewMatrix, 0);

GLES20.glUseProgram(bottleShaderProgramID);

// Draw the cube:
GLES20.glEnable(GLES20.GL_CULL_FACE);
GLES20.glCullFace(GLES20.GL_BACK);

GLES20.glVertexAttribPointer(vertexHandleBottle, 3, GLES20.GL_FLOAT, false, 0, cubeObject.getVertices());
GLES20.glVertexAttribPointer(normalHandleBottle, 3, GLES20.GL_FLOAT, false, 0, cubeObject.getNormals());

GLES20.glEnableVertexAttribArray(vertexHandleBottle);
GLES20.glEnableVertexAttribArray(normalHandleBottle);

// add light position and color
final float[] lightPositionInModelSpace=new float[] {0.0f, 1.1f, 0.0f, 1.0f};
GLES20.glUniform4f(lightPositionHandleBottle, lightPositionInModelSpace[0], lightPositionInModelSpace[1],
lightPositionInModelSpace[2], lightPositionInModelSpace[3]);
GLES20.glUniform3f(lightColorHandleBottle, 0.9f, 0.9f, 0.9f);

// create the normalMatrix for lighting calculations
final float[] normalMatrix=new float[16];
Matrix.invertM(normalMatrix, 0, modelViewMatrix, 0);
Matrix.transposeM(normalMatrix, 0, normalMatrix, 0);
// pass the normalMatrix to the shader
GLES20.glUniformMatrix4fv(normalMatrixHandleBottle, 1, false, normalMatrix, 0);

// extract the camera position for lighting calculations (last column of matrix)
// GLES20.glUniform3f(cameraPositionHandleBottle, normalMatrix[12], normalMatrix[13], normalMatrix[14]);

// set material properties
GLES20.glUniform3f(matAmbientHandleBottle, 0.0f, 0.0f, 0.0f);
GLES20.glUniform3f(matDiffuseHandleBottle, 0.1f, 0.9f, 0.1f);

// pass the model view matrix to the shader
GLES20.glUniformMatrix4fv(modelViewMatrixHandleBottle, 1, false, modelViewMatrix, 0);

// pass the model view projection matrix to the shader
// the "transpose" parameter must be "false" according to the spec, anything else is an error
GLES20.glUniformMatrix4fv(mvpMatrixHandleBottle, 1, false, modelViewProjection, 0);

GLES20.glDrawElements(GLES20.GL_TRIANGLES,
cubeObject.getNumObjectIndex(), GLES20.GL_UNSIGNED_SHORT, cubeObject.getIndices());

GLES20.glDisable(GLES20.GL_CULL_FACE);

// disable the enabled arrays after everything has been rendered
GLES20.glDisableVertexAttribArray(vertexHandleBottle);
GLES20.glDisableVertexAttribArray(normalHandleBottle);

ShaderFactory.checkGLError("MultiTargets renderFrame");
}

GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);

Renderer.getInstance().end();
}

我的顶点着色器:
attribute vec4 vertexPosition;
attribute vec3 vertexNormal;

uniform mat4 modelViewProjectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 normalMatrix;

// lighting
uniform vec4 uLightPosition;
uniform vec3 uLightColor;

// material
uniform vec3 uMatAmbient;
uniform vec3 uMatDiffuse;

// pass to fragment shader
varying vec3 vNormalEyespace;
varying vec3 vVertexEyespace;
varying vec4 vLightPositionEyespace;
varying vec3 vNormal;
varying vec4 vVertex;

void main()
{
// we can just take vec3() of a vec4 and it will take the first 3 entries
vNormalEyespace = vec3(normalMatrix * vec4(vertexNormal, 1.0));
vNormal = vertexNormal;
vVertexEyespace = vec3(modelViewMatrix * vertexPosition);
vVertex = vertexPosition;

// light position
vLightPositionEyespace = modelViewMatrix * uLightPosition;

gl_Position = modelViewProjectionMatrix * vertexPosition;
}

还有我的 fragment 着色器:
precision highp float; //apparently necessary to force same precision as in vertex shader

//lighting
uniform vec4 uLightPosition;
uniform vec3 uLightColor;

//material
uniform vec3 uMatAmbient;
uniform vec3 uMatDiffuse;

//from vertex shader
varying vec3 vNormalEyespace;
varying vec3 vVertexEyespace;
varying vec4 vLightPositionEyespace;
varying vec3 vNormal;
varying vec4 vVertex;

void main()
{
vec3 normalModel = normalize(vNormal);
vec3 normalEyespace = normalize(vNormalEyespace);
vec3 lightDirectionModel = normalize(uLightPosition.xyz - vVertex.xyz);
vec3 lightDirectionEyespace = normalize(vLightPositionEyespace.xyz - vVertexEyespace.xyz);

vec3 ambientTerm = uMatAmbient;
vec3 diffuseTerm = uMatDiffuse * uLightColor;
// calculate the lambert factor via cosine law
float diffuseLambert = max(dot(normalEyespace, lightDirectionEyespace), 0.0);
// Attenuate the light based on distance.
float distance = length(vLightPositionEyespace.xyz - vVertexEyespace.xyz);
float diffuseLambertAttenuated = diffuseLambert * (1.0 / (1.0 + (0.01 * distance * distance)));

diffuseTerm = diffuseLambertAttenuated * diffuseTerm;

gl_FragColor = vec4(ambientTerm + diffuseTerm, 1.0);
}

最佳答案

我终于解决了所有问题。
有 2 个问题可能对 future 的读者感兴趣。

  • 来自官方示例(当前 Vuforia 版本 4)的 Vuforia CubeObject 类具有错误的法线。它们并不都与顶点定义顺序相对应。如果您使用示例中的 CubeObject,请确保法线定义与面正确对应。 Vuforia 失败...
  • 正如怀疑的那样,我的 normalMatrix 构建错误。我们不能只反转转置 4x4 modelViewMatrix,我们需要首先从中提取左上角的 3x3 子矩阵,然后反转转置它。

  • 这是对我有用的代码:
      final Mat3 normalMatrixCube=new Mat3();
    normalMatrixCube.SetFrom4X4(modelViewMatrix);
    normalMatrixCube.invert();
    normalMatrixCube.transpose();

    不过,这段代码本身并没有那么有用,因为它依赖于我 randomly imported from this guy 的自定义类 Mat3。因为 Android 和 Vuforia 似乎都没有提供任何可以反转/转置 3x3 矩阵的矩阵类。这真的让我怀疑自己的理智——唯一适用于此类基本问题的代码必须依赖于自定义矩阵类?也许我只是做错了,我不知道......

    关于android - OpenGL ES 2.0 的漫反射着色器 : Light changes with camera movement (Vuforia on Android),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29505901/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com