Related
This is what happens when I draw switching from the black texture to the lime green one in a simple for loop. It seems to have bits from the previously drawn texture.
Here's a simplified version of how my renderer works
Init(): Create my VAO and attrib pointers and generate element buffer and indicies
Begin(): Bind my vertex buffer and map the buffer pointer
Draw(): Submit a renderable to draw which gets 4 vertecies in the vertex buffer each get a position, color, texCoords, and a Texture Slot
End(): I delete the buffer pointer, bind my VAO, IBO, and textures to their active texture slots and draw the elements.
I do this every frame (except init). What I don't understand is if I draw PER TEXTURE, only having one active then this doesn't happen. It's when I have multiple active textures and they are bound.
Here's my renderer
void Renderer2D::Init()
{
m_Textures.reserve(32);
m_VertexBuffer.Create(nullptr, VERTEX_BUFFER_SIZE);
m_Layout.PushFloat(2); //Position
m_Layout.PushUChar(4); //Color
m_Layout.PushFloat(2); //TexCoords
m_Layout.PushFloat(1); //Texture ID
//VA is bound and VB is unbound
m_VertexArray.AddBuffer(m_VertexBuffer, m_Layout);
unsigned int* indices = new unsigned int[INDEX_COUNT];
int offset = 0;
for (int i = 0; i < INDEX_COUNT; i += 6)
{
indices[i + 0] = offset + 0;
indices[i + 1] = offset + 1;
indices[i + 2] = offset + 2;
indices[i + 3] = offset + 2;
indices[i + 4] = offset + 3;
indices[i + 5] = offset + 0;
offset += 4;
}
m_IndexBuffer.Create(indices, INDEX_COUNT);
m_VertexArray.Unbind();
}
void Renderer2D::Begin()
{
m_VertexBuffer.Bind();
m_Buffer = (VertexData*)m_VertexBuffer.GetBufferPointer();
}
void Renderer2D::Draw(Renderable2D& renderable)
{
const glm::vec2& position = renderable.GetPosition();
const glm::vec2& size = renderable.GetSize();
const Color& color = renderable.GetColor();
const glm::vec4& texCoords = renderable.GetTextureRect();
const float tid = AddTexture(renderable.GetTexture());
DT_CORE_ASSERT(tid != 0, "TID IS EQUAL TO ZERO");
m_Buffer->position = glm::vec2(position.x, position.y);
m_Buffer->color = color;
m_Buffer->texCoord = glm::vec2(texCoords.x, texCoords.y);
m_Buffer->tid = tid;
m_Buffer++;
m_Buffer->position = glm::vec2(position.x + size.x, position.y);
m_Buffer->color = color;
m_Buffer->texCoord = glm::vec2(texCoords.z, texCoords.y);
m_Buffer->tid = tid;
m_Buffer++;
m_Buffer->position = glm::vec2(position.x + size.x, position.y + size.y);
m_Buffer->color = color;
m_Buffer->texCoord = glm::vec2(texCoords.z, texCoords.w);
m_Buffer->tid = tid;
m_Buffer++;
m_Buffer->position = glm::vec2(position.x, position.y + size.y);
m_Buffer->color = color;
m_Buffer->texCoord = glm::vec2(texCoords.x, texCoords.w);
m_Buffer->tid = tid;
m_Buffer++;
m_IndexCount += 6;
}
void Renderer2D::End()
{
Flush();
}
const float Renderer2D::AddTexture(const Texture2D* texture)
{
for (int i = 0; i < m_Textures.size(); i++) {
if (texture == m_Textures[i]) // Compares memory addresses
return i + 1; // Returns the texture id plus one since 0 is null texture id
}
// If the texture count is already at or greater than max textures
if (m_Textures.size() >= MAX_TEXTURES)
{
End();
Begin();
}
m_Textures.push_back((Texture2D*)texture);
return m_Textures.size();
}
void Renderer2D::Flush()
{
m_VertexBuffer.DeleteBufferPointer();
m_VertexArray.Bind();
m_IndexBuffer.Bind();
for (int i = 0; i < m_Textures.size(); i++) {
glActiveTexture(GL_TEXTURE0 + i);
m_Textures[i]->Bind();
}
glDrawElements(GL_TRIANGLES, m_IndexCount, GL_UNSIGNED_INT, NULL);
m_IndexBuffer.Unbind();
m_VertexArray.Unbind();
m_IndexCount = 0;
m_Textures.clear();
}
Here's my fragment shader
#version 330 core
out vec4 FragColor;
in vec4 ourColor;
in vec2 ourTexCoord;
in float ourTid;
uniform sampler2D textures[32];
void main()
{
vec4 texColor = ourColor;
if(ourTid > 0.0)
{
int tid = int(ourTid - 0.5);
texColor = ourColor * texture(textures[tid], ourTexCoord);
}
FragColor = texColor;
}
I appreciate any help, let me know if you need to see more code
i don't know if you need this anymore but for the the record
you have a logical problem in your fragment code
let's think if your "ourTid" bigger than 0 let's take 1.0f for example
you subtract 0.5f , we cast it to int(0.5) it's 0 for sure now let's say that we need the texture number 2 and do the same process 2-0.5 = 1.5 "cast it to int" = 1
definitely you will have the previous texture every time
now the solution is easy you should add 0.5 instead of subtract it to be sure that the numbers interpolation is avoided and you got the correct texture.
I have a problem on setting up two buffers for my shaders. I wanted to use Compute Shader, but the problem already starts in the Vertex Shader.
What I want: Two separate SSBO with particles inside that I can spin nd move individually.
How I want to start: Just put the initial values into VAOs, copy them into a SSBO in the vertex shader and process them in the Computer Shaders.
Problem: Both VAOs are created equally and the values are equal. However, when I want to copy the values into a SSBO the VAO breaks and only 512 values (which is half of the number of items) are further correct and the others partly have weird different values, what I can see from RenderDoc.
Have a look in my application.cpp
#include "application.hpp"
application::application()
{
this->initParticleSystem();
}
void application::initParticleSystem()
{
this->initializeWindow();
this->initializeOpenGL();
}
void application::runThread()
{
double lastFPStime = glfwGetTime();
int frameCounter = 0;
while (!glfwWindowShouldClose(m_RenderWindow))
{
this->run(frameCounter, lastFPStime);
}
}
void application::initializeWindow()
{
if (!glfwInit())
{
throw runtime_error("\n[ERROR] GLFW initialization failed!\n");
}
this->setupRenderWindow();
/// set key callback
this->setupKeyCallBack();
IOManager::getInstance()->setRenderWindow(m_RenderWindow);
}
void application::initializeOpenGL()
{
Log::logInit(m_Name, "OpenGL");
glewInit();
if (!glewIsSupported("GL_VERSION_4_6"))
{
throw std::runtime_error("\n[ERROR] Sorry, but you need an OpenGL 4.6 Core to run this program.\n");
}
/// get version info
Log::printSystemSettings();
this->initBuffers();
this->initBasicShader();
this->initComputeShader();
}
void application::initBuffers()
{
this->packVec4GridSizeSSBO(VORTEX_1_SEEDS_NR, SHADER_GRID_VOR_1_NR, m_GridPositionVaoHandle, m_PackedGridBufferHandle, { 0.,0. }, "Grid");
this->packVec4GridSizeSSBO(VORTEX_2_SEEDS_NR, SHADER_GRID_VOR_2_NR, m_VortexPositionVaoHandle, m_PackedVortexBufferHandle, { 0.,-0. }, "Vortex");
this->bindBuffers();
}
void application::initComputeShader()
{
this->initComputeShader(GRID_VELOCITY_NR, GRID_VELOCITY_SHADER);
}
void application::bindBuffers()
{
this->bindVertexBufferObject(VORTEX_1_SEEDS_NR, m_PackedGridBufferHandle, "Vortex 1");
this->bindVertexBufferObject(VORTEX_2_SEEDS_NR, m_PackedVortexBufferHandle, "Vortex 2");
}
void application::bindVertexBufferObject(unsigned int index, uint32_t &bufferHandle, string text)
{
glBindBuffer(GL_ARRAY_BUFFER, bufferHandle);
glVertexAttribPointer(index, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(index);
}
void application::packVec4GridSizeSSBO(unsigned int seedNumber, unsigned int shaderPosNumber, uint32_t &vaoHandle, uint32_t &packedBufferHandle, vec2f translate, string text)
{
constexpr ptrdiff_t ssboSize = sizeof(glm::vec4) * GRID_DIM_SQ;
constexpr ptrdiff_t packedBufferSize = ssboSize;
ptrdiff_t ssboOffset = 0;
this->initSeeds(packedBufferSize, ssboSize, packedBufferHandle, translate, text);
this->bindBufferToVertexArrayObject(vaoHandle, packedBufferHandle, seedNumber);
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, shaderPosNumber, packedBufferHandle, ssboOffset, ssboSize); /// Grid Positions
}
void application::bindBufferToVertexArrayObject(uint32_t &vaoHandle, uint32_t &bufferHandle, unsigned int seedNumber)
{
glGenVertexArrays(1, &vaoHandle);
glBindVertexArray(vaoHandle);
}
void application::initBasicShader()
{
glEnable(GL_POINT_SPRITE);
uint32_t vertex_shader_handle = IOManager::getInstance()->loadShader(PARTICLE_VERTEX_SHADER, GL_VERTEX_SHADER);
uint32_t fragment_shader_handle = IOManager::getInstance()->loadShader(PARTICLE_FRAGMENT_SHADER, GL_FRAGMENT_SHADER);
m_RenderProgramHandle = glCreateProgram();
glAttachShader(m_RenderProgramHandle, fragment_shader_handle);
glAttachShader(m_RenderProgramHandle, vertex_shader_handle);
glLinkProgram(m_RenderProgramHandle);
IOManager::getInstance()->checkProgramLinked(m_RenderProgramHandle, string(PARTICLE_VERTEX_SHADER) + ", " + string(PARTICLE_FRAGMENT_SHADER));
glDeleteShader(vertex_shader_handle);
glDeleteShader(fragment_shader_handle);
}
void application::initComputeShader(int index, string filePath)
{
uint32_t computeShaderHandle = IOManager::getInstance()->loadShader(filePath, GL_COMPUTE_SHADER);
m_ParticleShaders[index] = glCreateProgram();
glAttachShader(m_ParticleShaders[index], computeShaderHandle);
glLinkProgram(m_ParticleShaders[index]);
IOManager::getInstance()->checkProgramLinked(m_RenderProgramHandle, filePath);
Log::printProgramLog(m_ParticleShaders[index]);
/// delete shader as we're done with them.
glDeleteShader(computeShaderHandle);
}
void application::run(int &frameCounter, double &lastFPStime)
{
this->runParticleSystem();
IOManager::getInstance()->calculateTime(frameCounter, lastFPStime);
}
void application::runParticleSystem()
{
/// process user inputs
glfwPollEvents();
/// step through the simulation if not PAUSED
if (!paused)
{
glUseProgram(m_ParticleShaders[0]);
/// Number of invocations #grid_x * grid_y
glDispatchCompute(GRID_NUM_WORK_GROUPS, 1, 1);
//#TODO: all shaders but the Integrate-Shader can run parallel and don't need the barrier bit in between!
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
m_FrameNumber++;
}
this->runBasicShader();
glfwSwapBuffers(m_RenderWindow);
}
void application::runOpenGLBuffer()
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPointSize(PARTICLE_SIZE);
}
void application::runBasicShader()
{
this->runOpenGLBuffer();
glUseProgram(m_RenderProgramHandle);
glDrawArrays(GL_POINTS, 0, NUM_PARTICLES);
}
void application::initSeeds(ptrdiff_t packedBufferSize, ptrdiff_t positionSSBOSize, uint32_t &bufferHandle, vec2f translate, string text)
{
vector<glm::vec4> initialSeed(GRID_DIM_SQ);
for (int j = 0; j < GRID_DIM; j++) {
for (int i = 0; i < GRID_DIM; i++) {
int index = j * GRID_DIM + i;
/// Normalize positions for GPU to -1 <= xyPos <= 1
vec2f shaderPos = Utils::grid2ShaderDim(vec2i{ i, j });
initialSeed[index].x = shaderPos.x + translate.x;
initialSeed[index].y = shaderPos.y + translate.y;
initialSeed[index].z = index; /// Index of grid cell
initialSeed[index].w = 1;
}
}
this->saveDataInBuffer(packedBufferSize, positionSSBOSize, initialSeed, bufferHandle);
}
void application::saveDataInBuffer(ptrdiff_t packed_buffer_size, ptrdiff_t ssbo_size, vector<glm::vec4> dataVector, uint32_t &bufferHandle)
{
void* initialData = malloc(packed_buffer_size);
memset(initialData, 0, packed_buffer_size);
memcpy(initialData, dataVector.data(), ssbo_size);
glGenBuffers(1, &bufferHandle);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, bufferHandle);
glBufferStorage(GL_SHADER_STORAGE_BUFFER, packed_buffer_size, initialData, GL_DYNAMIC_STORAGE_BIT);
free(initialData);
}
... and my very basic vertex shader.glsl:
#version 460
#extension GL_ARB_separate_shader_objects : enable
// ---- INPUT -----------------------------------
layout (location = 0) in vec4 in_VortexPosition1;
layout (location = 1) in vec4 in_VortexPosition2;
// ---- OUTPUT ----------------------------------
layout (location = 0) out flat uint out_PosIndex;
out gl_PerVertex
{
vec4 gl_Position;
};
// ---- UNIFORM ---------------------------------
layout(std430, binding = 6) buffer grid_vortex1_block
{
vec4 gridVortex1[];
};
layout(std430, binding = 7) buffer grid_vortex2_block
{
vec2 gridVortex2[];
};
void main ()
{
out_PosIndex = uint(in_VortexPosition1.z);
// only half the values
gl_Position = vec4(gridVortex2[out_PosIndex].xy, 0, 1);
// works fine
//gl_Position = vec4(gridVortex1[out_PosIndex].xy, 0, 1);
}
And the Compute Shader.glsl:
#version 460
#extension GL_ARB_separate_shader_objects : enable
#define WORK_GROUP_SIZE 128
layout (local_size_x = WORK_GROUP_SIZE) in;
// ---- UNIFORM ---------------------------------
layout(std430, binding = 6) buffer grid_vortex1_block
{
vec4 gridVortex1[];
};
layout(std430, binding = 7) buffer grid_vortex2_block
{
vec2 gridVortex2[];
};
void main()
{
uint INDEX = gl_GlobalInvocationID.x;
// THIS OPERATION SCREWS UP EVERYTHING IN THE BUFFER, as you can see in pic3
gridVortex1[INDEX].xy += 0.2f;
gridVortex1[INDEX].xy -= 0.2f;
}
The following two pictures show the result. First, correct grid (e.g. vortex 1, not spinning yet), second, the half disappears after one frame for vortex 2.
Thank you for your help.
I am trying to implement picking by an int id, but it looks like my shader doesn't write anything, althought I can read the clear color properly.
vs, I skipped completely any matrix for debugging:
#version 330
#include semantic.glsl
layout (location = POSITION) in vec3 position;
uniform Transform0
{
mat4 view;
mat4 proj;
mat4 viewProj;
};
uniform Transform1
{
mat4[TRANSFORM1_SIZE] models;
};
uniform Parameters
{
// x = mesh baseVertex
// y = selected
// z = active
// w = id
ivec4[INDICES_SIZE] params;
};
out Block
{
flat int id;
} outBlock;
int getIndex()
{
int iBegin = 0;
int iEnd = params.length() - 1;
int l = iBegin;
int r = iEnd;
int i = 0;
if(params.length > 1)
{
do
{
i = int(((l + r) / 2.0f));
if (l == (r - 1))
if (l == 0 && gl_VertexID <= params[l].x || gl_VertexID <= params[l].x && gl_VertexID > params[l - 1].x)
return l;
else if(gl_VertexID > params[l].x && gl_VertexID <= params[r].x)
return r;
else
return 0;
else if (gl_VertexID == params[i].x)
return i;
else if (gl_VertexID < params[i].x)
r = i;
else if (gl_VertexID > params[i].x)
l = i;
} while (l < r);
}
return 0;
}
void main()
{
int index = getIndex();
mat4 model = models[index];
//gl_Position = proj * (view * (model * vec4(position, 1)));
gl_Position = vec4(4.0 * float(gl_VertexID % 2) - 1.0, 4.0 * float(gl_VertexID / 2) - 1.0, 0.0, 1.0);
outBlock.id = params[index].w;
}
fs, hardcoded value for the moment, output is 0 (FRAG_COLOR), tried also 1 but nothing:
#version 330
#include semantic.glsl
// Outgoing final color.
layout (location = FRAG_COLOR) out int outputColor;
in Block
{
flat int id;
} inBlock;
void main()
{
//outputColor = inBlock.id;
outputColor = 9;
}
Init phase, I have one fbo, called RESOLVE, with 3 attachements, one depth, one float color on 0 and one integer for picking on 1. Fbo is complete:
gl3.glBindTexture(GL_TEXTURE_2D, textureName.get(Texture.RESOLVE_ID));
gl3.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
gl3.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
gl3.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl3.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl3.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl3.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
gl3.glTexImage2D(GL_TEXTURE_2D, 0, GL_R32I, EC.viewer.size.x, EC.viewer.size.y, 0, GL_RED_INTEGER, GL_INT, null);
gl3.glGenFramebuffers(Framebuffer.MAX - (samples == 1 ? 1 : 0), framebufferName);
gl3.glBindFramebuffer(GL_FRAMEBUFFER, framebufferName.get(Framebuffer.RESOLVE));
gl3.glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, textureName.get(Texture.RESOLVE_DEPTH), 0);
gl3.glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureName.get(Texture.RESOLVE_COLOR), 0);
gl3.glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, textureName.get(Texture.RESOLVE_ID), 0);
if (gl3.glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
System.err.println("incomplete");
return false;
}
and render & reading, added also glFlush, glFinish and glPixelStorei but nothing:
gl3.glBindFramebuffer(GL_FRAMEBUFFER, framebufferName.get(Framebuffer.RESOLVE));
gl3.glDrawBuffer(GL_COLOR_ATTACHMENT1);
gl3.glClearBufferiv(GL_COLOR, 0, clearId.put(0, 0)); // we care clearing only red
gl3.glBindVertexArray(EC.meshManager.vertexArrayName.get(0));
gl3.glEnable(GL_DEPTH_TEST);
gl3.glUseProgram(program.name);
gl3.glDrawElements(GL_TRIANGLES, EC_Gl3MeshManager.ELEMENT_OPAQUE_COUNT, GL_UNSIGNED_INT, 0);
gl3.glDisable(GL_DEPTH_TEST);
gl3.glReadBuffer(GL_COLOR_ATTACHMENT1);
glm.vec._2.i.Vec2i window = new glm.vec._2.i.Vec2i(
EC.inputListener.mousePressed.getX(),
EC.viewer.size.y - EC.inputListener.mousePressed.getY() - 1);
System.out.println("window (" + window.x + ", " + window.y + ")");
gl3.glFlush();
gl3.glFinish();
gl3.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Get the red coordinate reading the pixel click from the color 1 buffer, we can use the clearId buffer
gl3.glReadPixels(window.x, window.y, 1, 1, GL_RED_INTEGER, GL_INT, clearId);
gl3.glReadBuffer(GL_COLOR_ATTACHMENT0);
As I said, if I clear with 10, I read 10, so that is working, the only problematic thing is my shader..
Can you spot the error, guys?
Edit: trying to debug, I am checking the attachment type on color 1
gl3.glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, clearId);
System.out.println("GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: " + clearId.get(0));
gl3.glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, clearId);
System.out.println("GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: " + clearId.get(0)+", tex: "+textureName.get(Texture.RESOLVE_ID));
I get:
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: 5890
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: 14, tex: 14
5890 is GL_TEXTURE, name looks correct
tried to use glFramebufferTexture2D, but I still get GL_TEXTURE type instead GL_TEXTURE_2D
Edit 2: trying to read the depth component, is always 0
Shame on me, the problem was the depth test, since I forgot to clean the buffer it was never passing
I have implemented a simple (slow) method that would imitate OpenGL immediate mode for drawing lines.
Each frame, I add a pair of vertices, that indicate lines to vector structure, as well as add some specified or default color to another vector structure.
void WindowsGraphicsManager::vertex(float x, float y, float z) {
vertices_.push_back(x);
vertices_.push_back(y);
vertices_.push_back(z);
colors_.push_back(vertexColor_.getR());
colors_.push_back(vertexColor_.getG());
colors_.push_back(vertexColor_.getB());
colors_.push_back(vertexColor_.getA());
}
And at the end of each frame I clear these vectors.
My render code looks like this:
void WindowsGraphicsManager::renderVertices(Mat4 mat) {
if (vertices_.size() == 0) {
return;
}
static Shader* shader = (Shader*) services_->getRM()->get(
Resource::SHADER, "openglimmediate");
glUseProgram(shader->getId());
shader->setMatrix4(Shader::WVP, mat);
glEnableVertexAttribArray(shader->getHandle(Shader::POS));
glVertexAttribPointer(shader->getHandle(Shader::POS),
3, GL_FLOAT, GL_FALSE, 0, &vertices_[0]);
glEnableVertexAttribArray(shader->getHandle(Shader::COL));
glVertexAttribPointer(shader->getHandle(Shader::COL),
4, GL_FLOAT, GL_FALSE, 0, &colors_[0]);
//LOGI("Before crash.");
//LOGI("Vertices size: %d", vertices_.size());
//LOGI("Colors size: %d", colors_.size());
//INFO: Vertices size: 607590
//INFO: Colors size: 810120
glDrawArrays(GL_LINES, 0, vertices_.size() / 3);
CHECK_GL_ERROR("Rendering lines.");
//LOGI("After crash.");
glDisableVertexAttribArray(shader->getHandle(Shader::COL));
glDisableVertexAttribArray(shader->getHandle(Shader::POS));
vertices_.clear();
colors_.clear();
}
When I add 607590 floats (divide by 3 for vertices) to vertices vector, rendering crashes on line with glDrawArrays function. Strange thing though, when I first maximize the window and render, then it works fine for model with 607590 floats, though it still crashes for model with ~800k flaots.
What might be causing this?
[Edit] Before rendering vertices I call one other method. After removing it, rendering stopped crashing, so I guess I do something wrong here.
inline void WindowsGraphicsManager::renderNode(
Node* node, Mat4 mat, bool ortho)
{
if (!node->getState(Node::RENDERABLE)) {
return;
}
// Retrieve model data.
Renderable* renderable = 0;
Resource* resource = 0;
if (node->hasResource(Resource::SPRITE)) {
resource = node->getResource(Resource::SPRITE);
renderable = dynamic_cast<Renderable*>(resource);
}
else if (node->hasResource(Resource::STATIC_OBJECT)) {
resource = node->getResource(Resource::STATIC_OBJECT);
renderable = dynamic_cast<Renderable*>(resource);
StaticObject* so = static_cast<StaticObject*>(resource);
// Check for frustum culling.
if (so->getBoundingVolume() != 0
&& so->getBoundingVolume()->isInFrustum(
services_->getCamera(), node->getPos())
== BoundingVolume::OUTSIDE)
{
return;
}
}
else if (node->hasResource(Resource::DYNAMIC_OBJECT)) {
resource = node->getResource(Resource::DYNAMIC_OBJECT);
renderable = dynamic_cast<Renderable*>(resource);
}
if (renderable == 0) {
LOGW("Renderable with name \"%s\" is null.",
node->getName().c_str());
return;
}
// Retrieve node shader or use default.
Shader* shader = static_cast<Shader*>(
node->getResource(Resource::SHADER));
if (shader == 0) {
LOGW("Unable to retrieve shader for node: %s.",
node->getName().c_str());
return;
}
int shaderId = shader->getId();
// Select shader program to use.
glUseProgram(shaderId);
CHECK_GL_ERROR("glUseProgram");
Mat4 res;
if (!ortho) {
Matrix::multiply(mat, node->getMatrix(), res);
}
else {
Mat4 tmp;
Mat4 pos;
Mat4 rot;
Mat4 scale;
Vec3 p = node->getPos();
Vec3 r = node->getRot();
Vec3 s = node->getScale();
float width = s.getX();
float height = s.getY();
float x = p.getX();
float y = p.getY();
Matrix::translate(pos, x, y, p.getZ());
Matrix::rotateXYZ(rot, r.getX(), r.getY(), r.getZ());
Matrix::scale(scale, width, height, 1.0f);
Matrix::multiply(mat, pos, res);
Matrix::multiply(res, rot, tmp);
Matrix::multiply(tmp, scale, res);
}
// World * View * Projection matrix.
shader->setMatrix4(Shader::WVP, res);
// World matrix.
shader->setMatrix4(Shader::W, node->getMatrix());
// Normal matrix.
if (shader->hasHandle(Shader::N)) {
Mat3 normalMatrix;
Matrix::toMat3(node->getMatrix(), normalMatrix);
shader->setMatrix3(Shader::N, normalMatrix);
}
// Light position.
float* lightPos = new float[lights_.size() * 3];
if (lights_.size() > 0 && shader->hasHandle(Shader::LIGHT_POS)) {
for (UINT i = 0; i < lights_.size(); i++) {
Vec3& pos = lights_[i]->getPos();
lightPos[i * 3 + 0] = pos.getX();
lightPos[i * 3 + 1] = pos.getY();
lightPos[i * 3 + 2] = pos.getZ();
}
shader->setVector3(Shader::LIGHT_POS, lightPos, lights_.size());
}
delete lightPos;
// Light count.
shader->setInt(Shader::LIGHT_COUNT, lights_.size());
//shader->setVector3(Shader::LIGHT_POS,
// services_->getEnv()->getSunPos()->toArray());
// Eye position.
shader->setVector3(Shader::EYE_POS,
services_->getCamera()->getPos().toArray());
// Fog color.
if (shader->hasHandle(Shader::FOG_COLOR)) {
shader->setVector3(Shader::FOG_COLOR,
services_->getEnv()->getFogColor());
}
// Fog density.
shader->setFloat(Shader::FOG_DENSITY, services_->getEnv()->getFogDensity());
// Timer.
shader->setFloat(Shader::TIMER,
(float) services_->getSystem()->getTimeElapsed());
// Bind combined buffer object.
if (renderable->getCBO() > 0) {
int stride = renderable->getVertexStride();
glBindBuffer(GL_ARRAY_BUFFER, renderable->getCBO());
if (shader->hasHandle(Shader::POS)) {
glEnableVertexAttribArray(shader->getHandle(Shader::POS));
glVertexAttribPointer(
shader->getHandle(Shader::POS), 3, GL_FLOAT, GL_FALSE,
stride, ((char*) 0) + renderable->getPosOffset());
}
if (renderable->getNormalOffset() != -1
&& shader->hasHandle(Shader::NORMAL)) {
glEnableVertexAttribArray(shader->getHandle(Shader::NORMAL));
glVertexAttribPointer(
shader->getHandle(Shader::NORMAL), 3, GL_FLOAT, GL_FALSE,
stride, ((char*) 0) + renderable->getNormalOffset());
}
if (renderable->getUVOffset() != -1 && shader->hasHandle(Shader::UV)) {
glEnableVertexAttribArray(shader->getHandle(Shader::UV));
glVertexAttribPointer(
shader->getHandle(Shader::UV), 2, GL_FLOAT, GL_FALSE,
stride, ((char*) 0) + renderable->getUVOffset());
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else {
return;
}
// Bind cube map.
if (node->hasResource(Resource::CUBE_MAP)
&& shader->hasHandle(Shader::CUBE_MAP)) {
glActiveTexture(GL_TEXTURE0);
CHECK_GL_ERROR("glActiveTexture");
CubeMap* t = static_cast<CubeMap*>(
node->getResource(Resource::CUBE_MAP));
glBindTexture(GL_TEXTURE_CUBE_MAP, t->getId());
CHECK_GL_ERROR("glBindTexture");
glUniform1i(shader->getHandle(Shader::CUBE_MAP), 0);
CHECK_GL_ERROR("glUniform1i");
}
int hTextures[8];
hTextures[0] = glGetUniformLocation(shader->getId(),
SHADER_MAIN_TEXTURE);
// Bind the texture.
vector<Resource*> textures = node->getResources(Resource::TEXTURE_2D);
UINT size = textures.size() < 8 ? textures.size() : 7;
UINT texture = 0;
for (UINT i = 0; i < size; i++) {
texture = i + 1;
const string& name = textures[i]->getName();
Texture2D* tex = static_cast<Texture2D*>(textures[i]);
string textName = name.substr(0, name.length() - 4);
hTextures[texture] = glGetUniformLocation(shader->getId(),
textName.c_str());
if (hTextures[texture] == -1) {
continue;
}
glActiveTexture(GL_TEXTURE0 + i + 1);
CHECK_GL_ERROR("glActiveTexture");
glBindTexture(GL_TEXTURE_2D, tex->getId());
CHECK_GL_ERROR("glBindTexture");
glUniform1i(hTextures[texture], texture);
CHECK_GL_ERROR("glUniform1i");
}
// Render node.
// BoundingVolume* volume = (*model->getBoundingVolumes())[i];
// if (model->hasBoundingVolumes()) {
// if (volume->isInFrustum(services_->getCamera(), node)
// == BoundingVolume::OUTSIDE) {
// continue;
// }
// }
int renderType;
switch (renderable->getRenderType()) {
case Renderable::RENDER_TYPE_POINTS:
renderType = GL_POINTS;
//glPointSize(renderable->getPointSize());
break;
case Renderable::RENDER_TYPE_LINES:
renderType = GL_LINES;
glLineWidth(renderable->getLineWidth());
break;
case Renderable::RENDER_TYPE_TRIANGLE_FAN:
renderType = GL_TRIANGLE_FAN;
break;
case Renderable::RENDER_TYPE_TRIANGLE_STRIP:
renderType = GL_TRIANGLE_STRIP;
break;
default:
renderType = GL_TRIANGLES;
break;
}
if (renderable->getWindingType() == Renderable::WINDING_TYPE_CCW) {
glFrontFace(GL_CCW);
}
else {
glFrontFace(GL_CW);
}
if (renderable->getCullFace()) {
glEnable(GL_CULL_FACE);
}
else {
glDisable(GL_CULL_FACE);
}
UINT renderCount = renderable->getRenderCount();
int lastTexture = 0;
for (UINT i = 0; i < renderable->getRenderCount(); i++) {
renderable->setRenderable(i);
// Ambient material color.
if (shader->hasHandle(Shader::AMBIENT)) {
shader->setVector3(Shader::AMBIENT,
renderable->getAmbient().toArray());
}
// Diffuse material color.
if (shader->hasHandle(Shader::DIFFUSE)) {
shader->setVector3(Shader::DIFFUSE,
renderable->getDiffuse().toArray());
}
// Specular material color.
if (shader->hasHandle(Shader::SPECULAR)) {
shader->setVector3(Shader::SPECULAR,
renderable->getSpecular().toArray());
}
// Specular material color intensity.
shader->setFloat(Shader::SPECULARITY, renderable->getSpecularity());
// Model transparency.
shader->setFloat(Shader::TRANSPARENCY, renderable->getTransparency());
// Bind main texture.
if (renderable->getTexture() != lastTexture
&& hTextures[0] != -1) {
lastTexture = renderable->getTexture();
if (shader->hasHandle(Shader::MAIN_TEXTURE)) {
if (lastTexture == 0) {
shader->setFloat(Shader::MAIN_TEXTURE, 0.0f);
}
else {
shader->setFloat(Shader::MAIN_TEXTURE, 1.0f);
}
}
glActiveTexture(GL_TEXTURE0);
CHECK_GL_ERROR("glActiveTexture");
glBindTexture(GL_TEXTURE_2D, renderable->getTexture());
CHECK_GL_ERROR("glBindTexture");
glUniform1i(hTextures[0], 0);
CHECK_GL_ERROR("glUniform1i");
}
if (renderable->getIBO() > 0) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
renderable->getIBO());
if (renderable->getIndexType() ==
Renderable::INDEX_TYPE_USHORT) {
glDrawElements(renderType,
renderable->getIndexCount(),
GL_UNSIGNED_SHORT,
0);
CHECK_GL_ERROR("glDrawElements");
}
else {
glDrawElements(renderType,
renderable->getIndexCount(),
GL_UNSIGNED_INT,
0);
CHECK_GL_ERROR("glDrawElementsInt");
}
}
else {
glDrawArrays(renderType, 0, renderable->getVertexCount() / 3);
CHECK_GL_ERROR("glDrawArrays");
}
}
//// Unbind the cube map.
//if (node->hasResource(Resource::CUBE_MAP)) {
// glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
//}
//// Unbind the textures.
//for (UINT i = 0; i < 8; i++) {
// glActiveTexture(GL_TEXTURE0 + i);
// CHECK_GL_ERROR("glActiveTexture");
// glBindTexture(GL_TEXTURE_2D, 0);
//}
}
So the problem was glBindBuffer() call after this part of code:
// Bind combined buffer object.
if (renderable->getCBO() > 0) {
int stride = renderable->getVertexStride();
glBindBuffer(GL_ARRAY_BUFFER, renderable->getCBO());
if (shader->hasHandle(Shader::POS)) {
glEnableVertexAttribArray(shader->getHandle(Shader::POS));
glVertexAttribPointer(
shader->getHandle(Shader::POS), 3, GL_FLOAT, GL_FALSE,
stride, ((char*) 0) + renderable->getPosOffset());
}
if (renderable->getNormalOffset() != -1
&& shader->hasHandle(Shader::NORMAL)) {
glEnableVertexAttribArray(shader->getHandle(Shader::NORMAL));
glVertexAttribPointer(
shader->getHandle(Shader::NORMAL), 3, GL_FLOAT, GL_FALSE,
stride, ((char*) 0) + renderable->getNormalOffset());
}
if (renderable->getUVOffset() != -1 && shader->hasHandle(Shader::UV)) {
glEnableVertexAttribArray(shader->getHandle(Shader::UV));
glVertexAttribPointer(
shader->getHandle(Shader::UV), 2, GL_FLOAT, GL_FALSE,
stride, ((char*) 0) + renderable->getUVOffset());
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
I had to move glBindBuffer() to the end of same method, and I also wrote glDisableVertexAttribArray for position, normal and UV buffers. This solved the problem, but I'm not sure why. I thought there is no need to call glDisableVertexAttribArray for VBO.
I think this problem is specific for NVIDIA drivers and gives first chance exception for nvoglv32.dll.
I write a program to implement environment mapping using OpenGL and Cg shader language.But the result is not very right.When calculate the color of the model,we will blend the reflection with a decal texture.A uniform parameter called reflectivity allows the application to control how reflective the material is.
Firstly I list my fragment Cg code:
void main_f(float2 texCoord : TEXCOORD0,
float3 R : TEXCOORD1,
out float4 color : COLOR,
uniform float reflectivity,
uniform sampler2D decalMap,
uniform samplerCUBE environmentMap)
{
//fetch reflected environment color
float3 reflectedColor = texCUBE(environmentMap,R);
//fetch the decal base coloe
float3 decalColor = tex2D(decalMap,texCoord);
color.xyz = lerp(reflectedColor,decalColor,reflectivity);//change !!!!!!!!
color.w = 1;
}
I set the uniform parameter reflectivity as 0.6.And the result is :
As we can see,the color information from the decal texture is lost.There is only color information from environment cube texture.And if I set reflectivity as 0,the model will be dark.
But if I change the color.xyz in the fragment cg code as :
color.xyz = decalColor;
I can get the right result(only has color from decal texture) :
And if I change the color.xyz in the fragment cg code as :
color.xyz = reflectedColor;
I can get the right result(only has color from environment cube texture) ,too:
And my question is :
Why it does not work when I blend the color information from decal texture with the color information from environment cube texture using Cg function lerp?
at last I list my cg vertex shader and cpp file:
vertex.cg:
void main_v(float4 position : POSITION,
float2 texCoord : TEXCOORD0,//decal texture
float3 normal : NORMAL,
out float4 oPosition : POSITION,
out float2 oTexCoord : TEXCOORD0,//out decal texture
out float3 R : TEXCOORD1,//reflective vector
uniform float3 eyePositionW,//eye position in world space
uniform float4x4 modelViewProj,
uniform float4x4 modelToWorld
)
{
modelViewProj = glstate.matrix.mvp;
oPosition = mul(modelViewProj,position);
oTexCoord = texCoord;
float3 positionW = mul(modelToWorld,position).xyz;
float3 N = mul((float3x3)modelToWorld,normal);
N = normalize(N);
float3 I = positionW - eyePositionW;//incident vector
R = reflect(I,N);
}
main.cpp:
#pragma comment(lib,"glew32.lib")
#pragma comment(lib,"GLAUX.LIB")
#pragma comment(lib,"cg.lib")
#pragma comment(lib,"cgGL.lib")
#include <GL/glew.h>
#include <GL/glut.h>
#include <GL/glaux.h>
#include <CG/cg.h>
#include <CG/cgGL.h>
#include "MonkeyHead.h"
#include <iostream>
#include <cmath>
using namespace std;
int loop;
/* Use enum to assign unique symbolic OpenGL texture names. */
enum {
TO_BOGUS = 0,
TO_DECAL,
TO_ENVIRONMENT,
};
const double myPi = 3.14159;
//for Cg shader
static CGcontext myCgContext;
static CGprofile myCgVertexProfile,myCgFragmentProfile;
static CGprogram myCgVertexProgram,myCgFragmentProgram;
static const char *myProgramName = "CgTest18CubeMapReflective",
*myVertexProgramFileName = "vertex.cg",
*myVertexProgramName = "main_v",
*myFragmentProgramFileName = "fragment.cg",
*myFragmentProgramName = "main_f";
static CGparameter myCgVertexParam_modelToWorld;
//bmp files for cube map
const char *bmpFile[6] = {"Data/1.bmp","Data/2.bmp","Data/3.bmp",
"Data/4.bmp","Data/5.bmp","Data/6.bmp"};
const char *decalBmpFile = "Data/decal.bmp";
static float eyeAngle = 0.53;
static float eyeHeight = 0.0f;
static float headSpain = 0.0f;
static const GLfloat vertex[4*6][3] = {
/* Positive X face. */
{ 1, -1, -1 }, { 1, 1, -1 }, { 1, 1, 1 }, { 1, -1, 1 },
/* Negative X face. */
{ -1, -1, -1 }, { -1, 1, -1 }, { -1, 1, 1 }, { -1, -1, 1 },
/* Positive Y face. */
{ -1, 1, -1 }, { 1, 1, -1 }, { 1, 1, 1 }, { -1, 1, 1 },
/* Negative Y face. */
{ -1, -1, -1 }, { 1, -1, -1 }, { 1, -1, 1 }, { -1, -1, 1 },
/* Positive Z face. */
{ -1, -1, 1 }, { 1, -1, 1 }, { 1, 1, 1 }, { -1, 1, 1 },
/* Negative Z face. */
{ -1, -1, -1 }, { 1, -1, -1 }, { 1, 1, -1 }, { -1, 1, -1 },
};
static float reflectivity = 0.6;
GLuint decalTexture;
bool animating = false;//enable animating or not
static void drawMonkeyHead()
{
static GLfloat *texCoords = NULL;
const int numVertices = sizeof(MonkeyHead_vertices)
/ (3 * sizeof(MonkeyHead_vertices[0]));
const float scaleFactor = 1.5;
//generate texcoords
texCoords = (GLfloat*)malloc(2 * numVertices * sizeof(GLfloat));
if (!texCoords)
{
cerr << "ERROR : Monkey head texcoords memory malloc failed !" << endl;
exit(1);
}
for (loop = 0;loop < numVertices;++loop)
{
texCoords[loop * 2] = scaleFactor * MonkeyHead_vertices[3 * loop];
texCoords[loop * 2 + 1] = scaleFactor * MonkeyHead_vertices[3 * loop + 1];
}
//use vertex array
//enable array
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//assign array data
glVertexPointer(3,GL_FLOAT,3 * sizeof(GLfloat),MonkeyHead_vertices);
glNormalPointer(GL_FLOAT,3 * sizeof(GLfloat),MonkeyHead_normals);
glTexCoordPointer(2,GL_FLOAT,2 * sizeof(GLfloat),texCoords);
glDrawElements(GL_TRIANGLES,3 * MonkeyHead_num_of_triangles,
GL_UNSIGNED_SHORT,MonkeyHead_triangles);
}
//read bmp image file
AUX_RGBImageRec *LoadBMP(const char *FileName)
{
FILE *File = NULL;
if(!FileName)
return NULL;
File = fopen(FileName,"r");
if (File)
{
fclose(File);
return auxDIBImageLoad(FileName);
}
return NULL;
}
//load decal texture from a bmp file
int loadDecalTexture()
{
int status = 1;
AUX_RGBImageRec *TextureImage = NULL;
if ((TextureImage = LoadBMP(decalBmpFile)))
{
glGenTextures(1,&decalTexture);
glBindTexture(GL_TEXTURE_2D,decalTexture);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,TextureImage->sizeX,
TextureImage->sizeY,0,GL_RGB,GL_UNSIGNED_BYTE,
TextureImage->data);//指定纹理
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//指定过滤模式
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
}
else
status = 0;
if (TextureImage)
{
if (TextureImage->data)
free(TextureImage->data);
free(TextureImage);
}
return status;
}
//load cube map from 6 bmp files
int loadCubeMap()
{
int status = 1;
AUX_RGBImageRec *TextureImage[6] = {NULL,NULL,NULL,NULL,NULL,NULL};
for (loop = 0;loop < 6;++loop)
{
if (!(TextureImage[loop] = LoadBMP(bmpFile[loop])))
{
cout << "ERROR :load bmp file " << loop << " failed !" << endl;
status = 0;
}
}
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGB, TextureImage[0] ->sizeX, TextureImage[0] ->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0] ->data);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGB, TextureImage[1] ->sizeX, TextureImage[1] ->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[1] ->data);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGB, TextureImage[2] ->sizeX, TextureImage[2] ->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[2] ->data);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGB, TextureImage[3] ->sizeX, TextureImage[3] ->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[3] ->data);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGB, TextureImage[4] ->sizeX, TextureImage[4] ->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[4] ->data);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGB, TextureImage[5] ->sizeX, TextureImage[5] ->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[5] ->data);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_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);
//free memory
for (loop = 0;loop < 6;++loop)
{
if (TextureImage[loop])
{
if (TextureImage[loop] ->data)
{
free(TextureImage[loop] ->data);
}
free(TextureImage[loop]);
}
}
return status;
}
//draw th surroundings as a cube with each face of
//the cube environment map applied.
void drawSurroundings(const GLfloat *eyePosition)
{
const float surroundingsDistance = 8;
glLoadIdentity();
gluLookAt(eyePosition[0],eyePosition[1],eyePosition[2],
0,0,0,0,1,0);
glScalef(surroundingsDistance,
surroundingsDistance,
surroundingsDistance);
glEnable(GL_TEXTURE_CUBE_MAP);
glBindTexture(GL_TEXTURE_CUBE_MAP,TO_ENVIRONMENT);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
glBegin(GL_QUADS);
for (loop = 0;loop < 4 * 6;++loop)
{
glTexCoord3fv(vertex[loop]);
glVertex3fv(vertex[loop]);
}
glEnd();
}
static void checkForCgError(const char *situation)
{
CGerror error;
const char *string = cgGetLastErrorString(&error);
if (error != CG_NO_ERROR) {
cout << "ERROR : " << myProgramName << situation << string << endl;
if (error == CG_COMPILER_ERROR) {
cout << cgGetLastListing(myCgContext) << endl;
}
exit(1);
}
}
//init Cg shaders
void initCg()
{
myCgContext = cgCreateContext();
myCgVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX);
cgGLSetOptimalOptions(myCgVertexProfile);
checkForCgError("selecting vertex profile");
myCgVertexProgram = cgCreateProgramFromFile(
myCgContext,
CG_SOURCE,
myVertexProgramFileName,
myCgVertexProfile,
myVertexProgramName,
NULL);
checkForCgError("Creating vertex Cg program from file");
cgGLLoadProgram(myCgVertexProgram);
checkForCgError("loading vertex program");
myCgFragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
cgGLSetOptimalOptions(myCgFragmentProfile);
checkForCgError("selecting fragment profile");
myCgFragmentProgram = cgCreateProgramFromFile(
myCgContext,
CG_SOURCE,
myFragmentProgramFileName,
myCgFragmentProfile,
myFragmentProgramName,
NULL);
checkForCgError("Creating fragment Cg program from file");
cgGLLoadProgram(myCgFragmentProgram);
checkForCgError("loading fragment program");
}
//compute rotate transformation matrix
void makeRotateMatrix(float angle,
float ax,float ay,float az,
float m[16])
{
float radians, sine, cosine, ab, bc, ca, tx, ty, tz;
float axis[3];
float mag;
axis[0] = ax;
axis[1] = ay;
axis[2] = az;
mag = sqrt(axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]);
if (mag) {
axis[0] /= mag;
axis[1] /= mag;
axis[2] /= mag;
}
radians = angle * myPi / 180.0;
sine = sin(radians);
cosine = cos(radians);
ab = axis[0] * axis[1] * (1 - cosine);
bc = axis[1] * axis[2] * (1 - cosine);
ca = axis[2] * axis[0] * (1 - cosine);
tx = axis[0] * axis[0];
ty = axis[1] * axis[1];
tz = axis[2] * axis[2];
m[0] = tx + cosine * (1 - tx);
m[1] = ab + axis[2] * sine;
m[2] = ca - axis[1] * sine;
m[3] = 0.0f;
m[4] = ab - axis[2] * sine;
m[5] = ty + cosine * (1 - ty);
m[6] = bc + axis[0] * sine;
m[7] = 0.0f;
m[8] = ca + axis[1] * sine;
m[9] = bc - axis[0] * sine;
m[10] = tz + cosine * (1 - tz);
m[11] = 0;
m[12] = 0;
m[13] = 0;
m[14] = 0;
m[15] = 1;
}
//compute translation transformation matrix
static void makeTranslateMatrix(float x, float y, float z, float m[16])
{
m[0] = 1; m[1] = 0; m[2] = 0; m[3] = x;
m[4] = 0; m[5] = 1; m[6] = 0; m[7] = y;
m[8] = 0; m[9] = 0; m[10] = 1; m[11] = z;
m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1;
}
//multiply a floar4x4 matrix by another float4x4 matrix
static void multMatrix(float dst[16],const float src1[16],const float src2[16])
{
for (int i = 0;i < 4;++i)
{
for (int j = 0;j < 4;++j)
{
dst[i * 4 + j] = src1[i * 4 + 0] * src2[0 * 4 + j] +
src1[i * 4 + 1] * src2[1 * 4 + j] +
src1[i * 4 + 2] * src2[2 * 4 + j] +
src1[i * 4 + 3] * src2[3 * 4 + j];
}
}
}
void init()
{
glewInit();
glClearColor(0.0,0.0,0.0,1.0);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
if (!loadDecalTexture())
{
cout << "ERROR : load decal texture from bmp file failed !" << endl;
exit(1);
}
glBindTexture(GL_TEXTURE_CUBE_MAP,TO_ENVIRONMENT);
if (!loadCubeMap())
{
cout << "ERROR : load cube map from bmp file failed !" << endl;
exit(1);
}
initCg();
}
void display()
{
const GLfloat eyePosition[4] = {6 * sin(eyeAngle),
eyeHeight,
6 * cos(eyeAngle),
1};
float tranlateMatrix[16],rotateMatrix[16],modelMatrix[16];
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
cgGLEnableProfile(myCgVertexProfile);
checkForCgError("enabling vertex profile");
cgGLEnableProfile(myCgFragmentProfile);
checkForCgError("enabling fragment profile");
cgGLBindProgram(myCgVertexProgram);
checkForCgError("binding vertex program");
cgGLBindProgram(myCgFragmentProgram);
checkForCgError("binding fragment program");
glLoadIdentity();
glTranslatef(0.0,0.0,-5.0);
glRotatef(headSpain,0,1,0);
//set some uniform parameters in Cg shader
cgGLSetParameter3fv(
cgGetNamedParameter(myCgVertexProgram,"eyePositionW"),
eyePosition);
checkForCgError("setting eyePositionW parameter");
makeRotateMatrix(headSpain,0,1,0,rotateMatrix);
makeTranslateMatrix(0.0,0.0,-5.0,tranlateMatrix);
multMatrix(modelMatrix,tranlateMatrix,rotateMatrix);
//set the Cg matrix parameter : modelToWorld
cgSetMatrixParameterfr(
cgGetNamedParameter(myCgVertexProgram,"modelToWorld"),
modelMatrix);
checkForCgError("setting modelToWorld parameter");
cgGLSetParameter1f(
cgGetNamedParameter(myCgFragmentProgram,"reflectivity"),
reflectivity);
checkForCgError("setting reflectivity parameter");
cgGLSetTextureParameter(
cgGetNamedParameter(myCgFragmentProgram,"decalMap"),
decalTexture);
checkForCgError("setting decalTexture parameter");
cgGLSetTextureParameter(
cgGetNamedParameter(myCgFragmentProgram,"environmentMap"),
TO_ENVIRONMENT);
checkForCgError("setting environmentMap parameter");
drawMonkeyHead();
cgGLDisableProfile(myCgVertexProfile);
checkForCgError("disabling vertex profile");
cgGLDisableProfile(myCgFragmentProfile);
checkForCgError("disabling fragment profile");
drawSurroundings(eyePosition);
glutSwapBuffers();
}
static void idle()
{
headSpain += 0.5;
if (headSpain > 360)
{
headSpain -= 360;
}
glutPostRedisplay();
}
static void keyboard(unsigned char key,int x,int y)
{
switch(key)
{
case ' ':
animating = !animating;
if (animating)
{
glutIdleFunc(idle);
}
else
glutIdleFunc(NULL);
break;
case 'r':
reflectivity += 0.1;
if (reflectivity > 1.0)
{
reflectivity = 1.0;
}
cout << "reflectivity : " << reflectivity << endl;
glutPostRedisplay();
break;
case 'R':
reflectivity -= 0.1;
if (reflectivity < 0.0)
{
reflectivity = 0.0;
}
cout << "reflectivity : " << reflectivity << endl;
glutPostRedisplay();
break;
case 27:
cgDestroyProgram(myCgVertexProgram);
cgDestroyContext(myCgContext);
exit(0);
break;
}
}
void reshape(int w,int h)
{
glViewport(0,0,(GLsizei)w,(GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,1,1.0,20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc,char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowPosition(0,0);
glutInitWindowSize(600,600);
glutCreateWindow("CubeMapReflection");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}
The first thing I see is that the lerp statement needs to have it's values reversed.
color.xyz = lerp(reflectedColor,decalColor,reflectivity);//change !!!!!!!!
should be
color.xyz = lerp(decalColor, reflectedColor, reflectivity);
because the lerp documentation says:
lerp(a, b, w) returns a when w = 0 and b when w = 1 and you want full decal when reflectivity = 0 and full reflected when reflectivity = 1.
I see that the effect you're trying to achieve is akin to GL_MODULATE. You will need to multiple the values together, not lerp between them. Try this, it should work and give you the effect you want.
color.xyz = (reflectedColor.xyz * reflectivity) * decalColor;