首页 > 解决方案 > 如何在窗口坐标中获取模型(对象)的位置

问题描述

我正在使用 OpenGL 和 c++ 构建一个应用程序,以在屏幕上显示一个透明对象,周围有多个灯光,并模拟来自透明对象的不同可能反射。然后我会在一个固定的相机位置截屏并随机移动物体以模拟反射并将其保存为本地文件夹中的 BMP 文件以及具有相同文件名的文本文件。

接下来,我需要在窗口坐标[x, y] 中获取对象位置并将其保存在我的输出文本文件中。

现在我的问题是在窗口坐标中获取对象的位置。例如。创建的窗口是 1920 X 1080。我需要与 [x * y] 格式相同的对象中心位置。

这是我的主要 cpp 文件

int RandGenerator()
{

std::random_device rd;
std::default_random_engine generator(rd());
std::uniform_real_distribution<double> distribution(-3.0, 3.0);
double number = distribution(generator);    

std::this_thread::sleep_for(std::chrono::milliseconds(100));

return number;

}

int RandGenerator_1()
{

std::random_device rd;
std::default_random_engine generator(rd());
std::uniform_real_distribution<double> distribution(-3.0, 3.0); 
double number1 = distribution(generator);
std::this_thread::sleep_for(std::chrono::milliseconds(100));

return number1;

}


int main()
{
mainWindow = Window(1920, 1080);    
mainWindow.initialise();

CreateObjects();
CreateShaders();

camera = Camera(glm::vec3(0.0f, 0.0f, 7.0f), glm::vec3(0.0f, 1.0f, 0.0f), 
-90.0f, 0.0f, 5.0f, 0.2f);

shinyMaterial = Material(4.0f, 156);
dullMaterial = Material(0.5f, 4);

groundfloor = Model();
groundfloor.LoadModel("res/models/blender/Floor.obj");  

blackhawk = Model();
blackhawk.LoadModel("res/models/blender/cup.obj");

cup2 = Model();
cup2.LoadModel("res/models/blender/cup.obj");

mainLight = DirectionalLight(1.0f, 1.0f, 1.0f, 
                            0.1f, 0.1f, 
                            0.5f, -1.0f, 20.0f);

unsigned int pointLightCount = 0;

pointLights[0] = PointLight(0.0f, 0.0f,1.0f,
                            1.0f, 1.0f,
                            3.0f, 0.0f, 1.0f,
                            1.0f, 0.2f, 0.1f);

pointLightCount++;

pointLights[1] = PointLight(1.0f, 1.0f, 1.0f,
                            1.0f, 1.0f,
                            -3.0f, 0.0f, 1.0f,
                            1.0f, 0.2f, 0.1f);

pointLightCount++;  


GLuint uniformProjection = 0, uniformModel = 0, uniformView = 0, 
   uniformEyePosition = 0,
       uniformSpecularIntensity =0,uniformShininess = 0;
glm::mat4 projection = glm::perspective(45.0f, 
 (GLfloat)mainWindow.getBufferWidth() / 
 (GLfloat)mainWindow.getBufferHeight(), 
 0.1f, 100.0f); 

//Main game Loop 
while (!mainWindow.getShouldClose()) 
{
    GLfloat now = glfwGetTime();
    deltaTime = now - lastTime;
    lastTime = now;

    // Handle user inputs and events
    glfwPollEvents();

    camera.keyControl(mainWindow.getKeys(), deltaTime);
    camera.mouseControl(mainWindow.getXchange(), mainWindow.getYchange());

    //clear the window
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    shaderList[0].UseShader();
    uniformProjection = shaderList[0].GetProjectionLocation();
    uniformModel = shaderList[0].GetModelLocation();
    uniformView = shaderList[0].GetViewLocation();
    uniformEyePosition = shaderList[0].GetEyePosition();
    uniformSpecularIntensity = shaderList[0].GetSpecularIntensityLoc();
    uniformShininess = shaderList[0].GetShininessLoc();

    glm::vec3 lowerLight = camera.GetCameraPosition();
    lowerLight.y -= 0.3f;

    glm::vec3 camerayaw = camera.GetCameraDirection();

    glm::vec3 dlightPos = mainLight.GetLightPos();      

    shaderList[0].SetDirectionalLight(&mainLight);
    shaderList[0].SetPointLights(pointLights, pointLightCount);
    shaderList[0].SetSpotLights(spotLights, spotLightCount);        

    glUniformMatrix4fv(uniformProjection, 1, GL_FALSE, 
    glm::value_ptr(projection));
    glUniformMatrix4fv(uniformView, 1, GL_FALSE, 
    glm::value_ptr(camera.calulateViewMatrix()));
    glUniform3f(uniformEyePosition, camera.GetCameraPosition().x, 
    camera.GetCameraPosition().y, camera.GetCameraPosition().z);        

    glEnable(GL_DEPTH_TEST);

    model = glm::mat4(1.0f);
    model = glm::translate(model, glm::vec3(0.0f, 0.0f, -0.46f));
    model = glm::scale(model, glm::vec3(0.5f, 0.5f, 0.5f));
    model = glm::rotate(model, 90.0f*toRad, glm::vec3(1.0f, 0.0f, 0.0f));
    glUniformMatrix4fv(uniformModel, 1, GL_FALSE, glm::value_ptr(model));
    dullMaterial.UseMaterial(uniformSpecularIntensity, uniformShininess);
    groundfloor.RenderModel();              

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glCullFace(GL_BACK);
    glEnable(GL_CULL_FACE);
    glDepthMask(GL_FALSE);

    glm::vec3 translation(RandGenerator(), RandGenerator_1(), 0.0f);

    model = glm::mat4(1.0f);
    model = glm::translate(model, translation);
    model = glm::scale(model, glm::vec3(1.0f, 1.0f, 1.0f));
    viewmat = camera.calulateViewMatrix();
    glm::mat4 model_view = projection * viewmat * model;        
    glUniformMatrix4fv(uniformModel, 1, GL_FALSE, glm::value_ptr(model));
    shinyMaterial.UseMaterial(uniformSpecularIntensity, uniformShininess);
    blackhawk.RenderModel();

    glDisable(GL_CULL_FACE);
    glDisable(GL_BLEND);        
    glDepthMask(GL_TRUE);


    glUseProgram(0);

    mainWindow.swapBuffers();
}

return 0;}

这是我的顶点着色器文件

#version 330

layout (location =0) in vec3 pos;
layout (location =1) in vec2 tex;
layout (location =2) in vec3 normal;

out vec4 vCol;
out vec2 TexCoords;
out vec3 NormalValue;
out vec3 FragPos;


uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform vec3 clipSpacePos;

void main()
{
gl_Position = projection * view *  model* vec4(pos, 1.0f);  

vCol = vec4(clamp(pos, 0.0f, 1.0f), 0.2f);

TexCoords = tex;

NormalValue = mat3(transpose(inverse(model))) * normal;

FragPos = (model* vec4(pos, 1.0f)).xyz;
} 

如果问题非常基本,请原谅我,我是 OpenGL 和编程的初学者。在此先感谢,输出图像:

图像

标签: c++openglmatrixgraphics3d

解决方案


要从场景坐标中获取屏幕坐标,您需要在其上应用所有变换矩阵并执行透视除法。

您没有提供任何示例代码,因此不清楚您使用的是旧 API 还是新 API……以及您得到的矩阵(或其他任何东西)和乘法顺序……

请参阅这两个相关的 QA:

对于数学的东西怎么做。

现在什么样的反射和透明度?

  1. 对于真正的交易,您需要光线追踪渲染

    例如这样的:

    但这些通常是时间昂贵的......

  2. 对于便宜的假货,您可以使用混合 + 环境立方体贴图技术

    透明度可以这样完成:

    对于反射,您只需添加环境立方体贴图。这意味着您在 a 中有一个(您的环境的)天空盒GL_CUBE_MAP_TEXTURE并计算从表面法线和方向到相机的反射光线......并将相应的立方体贴图纹素添加到结果颜色......它在旧式 API 中也是可行的,但很多更简单的是使用着色器。


推荐阅读