জিএলএসএল সংস্করণ 330 সহ একটি স্কাইবক্স কার্যকর করছে


14

আমি ওপেনজিএল 3.3 এবং জিএলএসএল সংস্করণ 330 এর সাথে কাজ করে একটি স্কাইবক্স পাওয়ার চেষ্টা করছি।

আমি ওয়েবে কোথাও একটি সম্পূর্ণ আধুনিক ওজিএল স্কাইবক্স টিউটোরিয়ালটি খুঁজে পেলাম না, তাই আমি একটি পুরানোকে আধুনিকীকরণ করেছি ( উল্লম্বের glVertexAttribPointer()পরিবর্তে ব্যবহার করে gl_Vertexইত্যাদি)। এটি বেশিরভাগ ক্ষেত্রেই কাজ করছে তবে 2 টি বড় বিবরণের জন্য:

স্কাইবক্সগুলি আরও আকাশের ত্রিভুজগুলির মতো, এবং টেক্সচারগুলি খারাপভাবে warেকে দেওয়া এবং প্রসারিত করা হয় (তারা তারকা ক্ষেত্র বলে মনে করা হয়, আমি একটি কালো পটভূমিতে রেখার সময় পেয়েছি)। আমি 99% নিশ্চিত যে এটি কারণ আমি পুরানো টিউটোরিয়ালগুলি পুরোপুরি সঠিকভাবে পোর্ট করি নি।

এখানে আমার স্কাইবক্স ক্লাস:

static ShaderProgram* cubeMapShader = nullptr;

static const GLfloat vertices[] = 
{
    1.0f, -1.0f,  1.0f,
    1.0f,  1.0f,  1.0f,
    1.0f,  1.0f, -1.0f,
    -1.0f, -1.0f,  1.0f,
    -1.0f, -1.0f, -1.0f,
    -1.0f,  1.0f, -1.0f,
    -1.0f,  1.0f,  1.0f,
    -1.0f,  1.0f, -1.0f,
    1.0f,  1.0f, -1.0f,
    1.0f,  1.0f,  1.0f,
    -1.0f,  1.0f,  1.0f,
    -1.0f, -1.0f,  1.0f,
    1.0f, -1.0f,  1.0f,
    1.0f, -1.0f, -1.0f,
    -1.0f, -1.0f, -1.0f,
    1.0f, -1.0f,  1.0f,
    -1.0f, -1.0f,  1.0f,
    -1.0f,  1.0f,  1.0f,
    1.0f,  1.0f,  1.0f,
    -1.0f, -1.0f, -1.0f,
    1.0f, -1.0f, -1.0f,
    1.0f,  1.0f, -1.0f,
    -1.0f,  1.0f, -1.0f
};

Skybox::Skybox(const char* xp, const char* xn, const char* yp, const char* yn, const        char* zp, const char* zn)
{
if (cubeMapShader == nullptr)
    cubeMapShader = new ShaderProgram("cubemap.vert", "cubemap.frag");

    texture = SOIL_load_OGL_cubemap(xp, xn, yp, yn, zp, zn, SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS);

    glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
    glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

    glGenVertexArrays(1, &vaoID);
    glBindVertexArray(vaoID);
    glGenBuffers(1, &vboID);
    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
    glBindVertexArray(0);

    scale = 1.0f;
}

Skybox::~Skybox()
{

}

void Skybox::Render()
{
    ShaderProgram::SetActive(cubeMapShader);
    glDisable(GL_DEPTH_TEST);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
    cubeMapShader->Uniform1i("SkyTexture", 0);
    cubeMapShader->UniformVec3("CameraPosition", Camera::ActiveCameraPosition());
    cubeMapShader->UniformMat4("MVP", 1, GL_FALSE, Camera::GetActiveCamera()->GetProjectionMatrix() * Camera::GetActiveCamera()->GetViewMatrix() * glm::mat4(1.0));
    glBindVertexArray(vaoID);
    glDrawArrays(GL_QUADS, 0, 24);
    glBindVertexArray(0);
    glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}

ভার্টেক্স শ্যাডার:

#version 330 
layout(location = 0) in vec3 Vertex;

uniform vec3 CameraPosition;
uniform mat4 MVP;

out vec3 Position;

void main()
{
    Position = Vertex.xyz;
    gl_Position = MVP * vec4(Vertex.xyz + CameraPosition, 1.0);
}

খণ্ড শ্যাডার:

#version 330 compatibility

uniform samplerCube SkyTexture;

in vec3 Position;

void main()
{
    gl_FragColor = textureCube(SkyTexture, Position);
}

এখানে চটকদার উদাহরণ। কেউ যদি জিএলএসএলকে ভালভাবে জানেন (আমি এখনও এটি শিখছি) বা স্কাইবক্সগুলি দেখে নিতে পারেন তবে আপনি যে কোনও সহায়তা দিতে পারেন তা আমি প্রশংসা করব। এছাড়াও, কুডোস যদি আপনি আমাকে শিখতে পারেন কিভাবে কীভাবে খণ্ড শেডারে নন-অবহিত ফাংশনগুলি ব্যবহার করতে হয় তবে আমাকে জিএসএসএল 330 এর সামঞ্জস্যতা প্রোফাইলটি ব্যবহার করতে হবে না।


সম্পাদনা: প্রসারিত টেক্সচারগুলির সাথে সাথেই সমস্যাটি পাওয়া গেল: আমি ভার্টেক্স শ্যাডারের Position = Vertex.xyxপরিবর্তে ব্যবহার করছিলাম Position = Vertex.xyz। উফ। তবে ত্রিভুজ ত্রুটি এখনও বিদ্যমান।


1
কিউব্যাপের টেক্সচার সহ একটি স্কাইবক্স রেন্ডার করতে আপনার কেবলমাত্র 4 টি শীর্ষ (পূর্ণ স্ক্রিন কোয়াড) প্রয়োজন। আপনার কেবলমাত্র একটি ভার্টেক্স শ্যাডার দরকার যা ক্যামেরা এবং অভিক্ষেপের উপর ভিত্তি করে সঠিক টেক্সচারের স্থানাঙ্কগুলি গণনা করে।
মিসেল

এটি একটি চূড়ান্ত সমস্যা হতে পারে। আপনি কি পুরো বাক্সটি পেয়েছেন কিনা তা দেখতে ব্যাকফেস কুলিং অক্ষম করার চেষ্টা করেছেন?
pwny

@pwny, আমি এটি ভেবে দেখিনি। আমি চেষ্টা করেছিলাম, এবং এটি কার্যকর হয়নি, তবে আমি দেখতে পাচ্ছি কীভাবে এটি এটি ফেলে দেওয়া যেতে পারে। পরামর্শের জন্য ধন্যবাদ.
sm81095

@ এমসেল, আমি এই পদ্ধতির কথা শুনেছি, তবে আমি এটির জন্য অনলাইনে কোনও টিউটোরিয়াল পাইনি, এবং আমি এখনও জিএসএসএল শেখার প্রক্রিয়াতে রয়েছি। আপনি কীভাবে এটি করবেন সে সম্পর্কে যদি আপনি একটি উদাহরণ বা কোনও লিঙ্ক সরবরাহ করতে পারেন তবে আমি এটির প্রশংসা করব।
sm81095

উত্তর:


29

যদিও এই উত্তরটি আপনার পদ্ধতির সাথে ভুল তা জানায় না, এটি স্কাইবক্সগুলি রেন্ডার করার একটি সহজ উপায় উপস্থাপন করে।

Ditionতিহ্যবাহী উপায় (টেক্সচার্ড কিউব)

স্কাইবক্স তৈরির জন্য সোজা উপায় হ'ল ক্যামেরার অবস্থানকে কেন্দ্র করে একটি টেক্সচারযুক্ত কিউব সরবরাহ করা। কিউবের প্রতিটি মুখ দুটি ত্রিভুজ এবং একটি 2 ডি টেক্সচার (বা একটি অ্যাটলাসের অংশ) নিয়ে গঠিত। জমিনের স্থানাঙ্কের কারণে প্রতিটি মুখের নিজস্ব শীর্ষকোষ প্রয়োজন। এই পদ্ধতির সংলগ্ন মুখগুলির সীমগুলিতে সমস্যা রয়েছে, যেখানে টেক্সচারের মানগুলি যথাযথভাবে বিভক্ত হয় না।

কিউবম্যাপ টেক্সচার সহ কিউব

প্রচলিত উপায়ে যেমন, একটি টেক্সচারযুক্ত ঘনক ক্যামেরার চারপাশে রেন্ডার করা হয়। ছয় 2 ডি টেক্সচার ব্যবহার না করে, একটি একক কিউব্যাপ টেক্সচার ব্যবহার করা হয়। ক্যামেরা কিউবের অভ্যন্তরে কেন্দ্রীভূত হওয়ায়, ভারেক্টেক্স কিউব্যাপের নমুনা ভেক্টরগুলির সাথে একের পর এক মানচিত্রকে স্থানাঙ্ক করে। সুতরাং জাল তথ্যগুলির জন্য টেক্সচারের স্থানাঙ্কগুলির প্রয়োজন হয় না এবং সূচি বাফার ব্যবহার করে শীর্ষগুলির মুখগুলির মধ্যে ভাগ করা যায়।

GL_TEXTURE_CUBE_MAP_SEAMLESS সক্ষম করা থাকলে এই পদ্ধতিটিও সিমগুলির সমস্যা সমাধান করে।

সহজ (আরও ভাল) উপায়

একটি কিউব রেন্ডার করার সময় এবং ক্যামেরাটি এর ভিতরে থাকে, পুরো ভিউপোর্টটি পূর্ণ হয়ে যায়। স্কাইবক্সের পাঁচটি পর্যন্ত মুখ যেকোন সময় আংশিকভাবে দৃশ্যমান হতে পারে। কিউব ফেসগুলির ত্রিভুজগুলি প্রজেক্ট করা হয় এবং ভিউপোর্টে ক্লিপ করা হয় এবং কিউব্যাপের স্যাম্পলিং ভেক্টরগুলি শীর্ষে অবস্থিত হয় ices এই কাজ অপ্রয়োজনীয়।

পুরো ভিউপোর্টটি পূরণ করে একটি একক কোয়াড পূরণ করা সম্ভব এবং কোণগুলিতে কিউব্যাপের স্যাম্পলিং ভেক্টর গণনা করা সম্ভব। যেহেতু কিউব্যাপের স্যাম্পলিং ভেক্টরগুলি ভার্টেক্সের স্থানাঙ্কগুলির সাথে মেলে, তাই তারা বিশ্ব স্পেসে ভিউপোর্টের স্থানাঙ্কগুলিকে অপ্রজেক্ট করে গণনা করা যায়। এটি ভিউপোর্টে বিশ্ব স্থানাঙ্কের বিপরীত এবং ম্যাট্রিকগুলি উল্টিয়ে অর্জন করা যেতে পারে। এছাড়াও আপনি নিশ্চিত করুন যে আপনি জেড-বাফার লিখতে অক্ষম করেছেন বা একটি মান লিখবেন যা যথেষ্ট পরিমাণে রয়েছে।

নীচে ভার্টেক্স শ্যাডার যা এটি সম্পাদন করে:

#version 330
uniform mat4 uProjectionMatrix;
uniform mat4 uWorldToCameraMatrix;

in vec4 aPosition;

smooth out vec3 eyeDirection;

void main() {
    mat4 inverseProjection = inverse(uProjectionMatrix);
    mat3 inverseModelview = transpose(mat3(uWorldToCameraMatrix));
    vec3 unprojected = (inverseProjection * aPosition).xyz;
    eyeDirection = inverseModelview * unprojected;

    gl_Position = aPosition;
} 

aPositionশীর্ষস্থানীয় স্থানাঙ্ক {-1,-1; 1,-1; 1,1; -1,1}। শ্যাডার eyeDirectionমডেল-ভিউ-প্রজেকশন ম্যাট্রিক্সের বিপরীত দিয়ে গণনা করে। তবে বিবর্তনটি প্রক্ষেপণ এবং বিশ্ব-থেকে-ক্যামেরা ম্যাট্রিক্সের জন্য বিভক্ত। এটি কারণ ক্যামেরার অবস্থান নির্মূল করতে ক্যামেরা ম্যাট্রিক্সের কেবলমাত্র 3x3 অংশ ব্যবহার করা উচিত। এটি ক্যামেরাটিকে স্কাইবক্সের কেন্দ্রে সারিবদ্ধ করে। আমার ক্যামেরায় কোনও স্কেলিং বা শিয়ারিং না থাকায় বিপরীতটি সরানোতে সরল করা যায়। প্রজেকশন ম্যাট্রিক্সের বিপরীতটি একটি ব্যয়বহুল ক্রিয়াকলাপ এবং প্রাক-প্রাক্কুলেট করা যেতে পারে, তবে এই কোডটি ভার্টেক্স শেডার দ্বারা কার্যকরভাবে ফ্রেম প্রতি মাত্র চার বার কার্যকর করা হয়, এটি সাধারণত একটি নন-ইস্যু।

খণ্ড শ্যাডার eyeDirectionভেক্টর ব্যবহার করে কেবল একটি টেক্সচার লকআপ সম্পাদন করে :

#version 330
uniform samplerCube uTexture;

smooth in vec3 eyeDirection;

out vec4 fragmentColor;

void main() {
    fragmentColor = texture(uTexture, eyeDirection);
}

নোট করুন যে সঙ্গতি মোড আপনি প্রতিস্থাপন করা প্রয়োজন পরিত্রাণ পেতে textureCubeশুধু সঙ্গে textureএবং নিজেকে আউটপুট পরিবর্তনশীল উল্লেখ করুন।


আমি মনে করি আপনারও উল্লেখ করা উচিত, যে ম্যাট্রিক্স বিপরীকরণ একটি ব্যয়বহুল প্রক্রিয়া, তাই এটি ক্লায়েন্ট-সাইড কোডে আরও ভাল হয়।
aktartar

1
পূর্ণস্ক্রিন কোয়াডের 4 ভার্টের জন্য আমি মনে করি না যে আমাদের বিপর্যয়ের ব্যয় সম্পর্কে খুব বেশি চিন্তা করা দরকার (বিশেষত জিপিইউ 4 বার এটি করার পরেও সম্ভবত সিপিইউ একবার করার চেয়ে দ্রুততর হবে)।
ম্যাক্সিমাস মিনিমাস

1
ভাবেনদের কাছে কেবল একটি সহায়ক নোট, জিএলএসএল ইএস 1.0 (জিএল ইএস 2.0 এর জন্য ব্যবহৃত) প্রয়োগ করে নাinverse()
স্টিভেন লু

uWorldToCameraMatrix কি ক্যামেরার এমভিপি রূপান্তর করে?
সিডার

@ সিদার না, এটি কেবলমাত্র মডেলভিউ ম্যাট্রিক্স, প্রোজেকশনটি পৃথক।
মিসেল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.