First off, this is a Uni assignment, but the lecturer is stumped too.
I am trying to imitate a heat lamp. The goal is to mimic what a thermal camera might see while looking at the sphere which is under the influence of the heat lamp.
To do this I need to get information about the heat values of the vertices/fragments from the previous frame, I know that OpenGL doesn't provide a way to do this so I need to 'export' the values back to C++ so that C++ can forward them to the next frame. How do I do that? I was thinking with a texture but ran into some problems, likely related to the ones mentioned in another issue I've been having with the code.
Here is the fragment shader:
const float lightWeighting = 0.75;
const float textureWeighting = 0.25;
const float PI = 3.14;
const float lightIntensity = 1.0;
const float constFudge = 0.025;
const float linearFudge = 0.025;
const float quadraticFudge = 0.05;
float rend = 250.0;
float rstart = 50.0;
uniform float Intensity;
uniform sampler2D grabTexture;
//varying sampler2D HeatValues
varying vec3 Normal;
varying vec3 Vertex;
varying vec2 texCoord;
void main(void)
{
vec3 pigPos = Vertex;
vec3 normPigPos = normalize(pigPos);
vec3 lightPos = vec3(gl_LightSource[0].position.xyz);
vec3 normLightPos = normalize(lightPos);
float effectiveIntesity;
vec3 normNormal = normalize(vec3(Normal.xyz));
vec3 t = vec3(pigPos - lightPos);
float distToLight = length(t);
float d = dot(normNormal.xyz, normLightPos.xyz);
if(d > 0.0)//facing the light
{
float falloff;
if( distToLight < rstart )
falloff = 1.0;
else
if( distToLight > rend )
falloff = 0.0;
else
{
falloff = rend-distToLight / rend-rstart;
}
effectiveIntesity = d*lightIntensity * falloff;
effectiveIntesity = d*lightIntensity * (1.0/(constFudge + (linearFudge*distToLight) +(quadraticFudge*distToLight*distToLight)));
}
else
{
effectiveIntesity = 0.0;
}
//TODO: change the colour of the pixel
vec4 lightingColour = vec4(vec4( 1.0 ) * effectiveIntesity); //TODO: improve
//gl_FragColor = lightingColour;
//texturing stuff
//http://www.opengl-tutorial.org/beginners-tutorials/tutorial-5-a-textured-cube/
vec4 textureColour = vec4(texture2D(grabTexture, texCoord.xy)); // TODO: why is this blank?
vec4 col = vec4(textureColour.rgb, 1.0);
col.r *= 1.0;
col.g *= 1.0;
gl_FragColor = (col);
//gl_FragColor = (lightingColour * lightWeighting) + (textureColour.rgb * textureWeighting);
//simple check to make sure that shader compiles
vec3 lP = vec3(abs(gl_LightSource[0].position.x/100), abs(gl_LightSource[0].position.y/100), abs(gl_LightSource[0].position.z/100));
vec4 r = vec4( lP.x, lP.y, lP.z, 1.0 );
gl_FragColor = r;
gl_FragColor = (lightingColour * lightWeighting) + (r * textureWeighting);
}
Edit:
I've had a go at doing what was suggested by user111821 and this is where I am now. My new issue is trying to get the heat texture to render to confirm that the shader can use it, however doing so causes the skin texture to render.
The final version of this will need both textures being used with some lighting contributing to the final pixel values of the sphere.
Revised Fragment Shader:
const float lightWeighting = 0.5;
const float textureWeighting = 0.25;
const float heatWeighting = 0.25;
const float PI = 3.14;
const float lightIntensity = 1.0;
const float constFudge = 0.025;
const float linearFudge = 0.025;
const float quadraticFudge = 0.05;
float rend = 250.0;
float rstart = 50.0;
uniform float Intensity;
uniform sampler2D grabTexture;
uniform sampler2D HeatValues;
varying vec3 Normal;
varying vec3 Vertex;
varying vec2 texCoord;
void main(void)
{
vec3 pigPos = Vertex;
vec3 normPigPos = normalize(pigPos);
vec3 lightPos = vec3(gl_LightSource[0].position.xyz);
vec3 normLightPos = normalize(lightPos);
float effectiveIntesity;
vec3 normNormal = normalize(vec3(Normal.xyz));
vec3 t = vec3(pigPos - lightPos);
float distToLight = length(t);
float d = dot(normNormal.xyz, normLightPos.xyz);
if(d > 0.0)//facing the light
{
float falloff;
if( distToLight < rstart )
falloff = 1.0;
else
if( distToLight > rend )
falloff = 0.0;
else
{
falloff = rend-distToLight / rend-rstart;
}
effectiveIntesity = d*lightIntensity * falloff;
effectiveIntesity = d*lightIntensity * (1.0/(constFudge + (linearFudge*distToLight) +(quadraticFudge*distToLight*distToLight)));
}
else
{
effectiveIntesity = 0.0;
}
//TODO: change the colour of the pixel
vec4 lightingColour = vec4(vec4( 1.0 ) * effectiveIntesity); //TODO: improve
//gl_FragColor = lightingColour;
//texturing stuff
//http://www.opengl-tutorial.org/beginners-tutorials/tutorial-5-a-textured-cube/
vec4 textureColour = vec4(texture2D(grabTexture, texCoord.xy)); // TODO: why is this blank?
//vec4 col = vec4(textureColour.rgb, 1.0);
//col.r *= 1.0;
//col.g *= 1.0;
gl_FragColor = (textureColour);
vec4 heatColour = vec4(texture2D(HeatValues, texCoord.xy));
gl_FragColor = heatColour;
//gl_FragColor = (lightingColour * lightWeighting) + (textureColour * textureWeighting) + (heatColour * heatWeighting);
//simple check to make sure that shader compiles
vec3 lP = vec3(abs(gl_LightSource[0].position.x/100), abs(gl_LightSource[0].position.y/100), abs(gl_LightSource[0].position.z/100));
vec4 r = vec4( lP.x, lP.y, lP.z, 1.0 );
//gl_FragColor = r;
//gl_FragColor = (lightingColour * lightWeighting) + (r * textureWeighting);
}
This a snippet of the class which is doing a bunch of C++ side of OpenG, the header file has been prepended for reference:
#pragma once
#include "stdafx.h"
class NA_Pig
{
private:
object_type pigObj;
unsigned char* rawLoadedTexture = NULL;
unsigned char* heatValuesPsudoTexture = NULL;
GLuint heatValuesTexID;
public:
NA_Pig();
~NA_Pig();
void draw();
//void loadShader();
vec3 pos;
int pigShader = 0;
void init();
};
void NA_Pig::draw()
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glTranslatef(pos.x, pos.y, pos.z);
glShadeModel(GL_SMOOTH);
extern cRenderClass graphics;
//Shader Stuff
//cShader *pList = graphics.ShaderInfo.getList();
//int shdr = 1;
//if (shdr >= graphics.ShaderInfo.shaderCount())
//{
// printf("Error: Can't access requested shader\n");
// shdr = 0;
//}
//// enable shader program..
//glUseProgram(pList[shdr].program());
//glUniform1fv(glGetAttribLocation(shaderID, variableNameAsString), sizeOfArray, valueAsArray)
//glUniform1f(glGetAttribLocation(shaderID, variableNameAsString), value);
//glUseProgram(shaderID);
//glutSolidSphere(12, 120, 2);
int size = 50;
glScaled(size, size, size);
// MATERIAL PROPERTISE
GLfloat ambient[4] = { 1.0,1.0,1.0,1.0 };
GLfloat diffuse[4] = { 1.0,1.0,1.0,1.0 };
GLfloat specular[4] = { 1.0,1.0,1.0,1.0 };
//glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
//glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
//glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
// activate texture for application is shader
//https://www.opengl.org/archives/resources/code/samples/glut_examples/examples/examples.html
glEnable(GL_TEXTURE_2D);
//apparently the shader needs this
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, rawLoadedTexture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCREEN_WIDTH*SCREEN_HEIGHT, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, &heatValuesPsudoTexture);
glActiveTexture(pigObj.id_texture); //the shader can use this texture
glActiveTexture(heatValuesTexID);
cShader *pList = graphics.ShaderInfo.getList();
glUseProgram( pList[1].program()); //shader on: no pig // fixed, was vertex shader being empty, replaced it with intensity.vert
//shader off: ambient light only (tiny amount of diffuse or an illusion?)
extern NA_MathsLib na_maths;
float intensity = (float) na_maths.dice(100);
glUniform1i(pList[1].get_grabLoc(), pigObj.id_texture);
glUniform1f(pList[1].intensity(), intensity);
glUniform1f(pList[1].get_heatValueGrabLoc(), heatValuesTexID);
//glutSolidSphere(2, 15, 2);
pigObj.render();
glActiveTexture(GL_TEXTURE0);
glDisable(GL_TEXTURE_2D);
glUseProgram(0); //disable pig heatlamp shader
glPopMatrix();
}
void NA_Pig::init()
{
int x, y, comp;
rawLoadedTexture = stbi_load("Pig/pig.bmp", &x, &y, &comp, 4);
if (rawLoadedTexture == NULL)
std::cout << "NA_Pig::init - stbi_load returned null\n";
//https://open.gl/textures
//https://open.gl/content/code/c3_multitexture.txt
//texturing stuff
glActiveTexture(GL_TEXTURE1);
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, x, y, 0, GL_RGB, GL_UNSIGNED_BYTE, rawLoadedTexture);
//heat lamp psudo texture
glActiveTexture(GL_TEXTURE2);
GLuint heat;
glGenTextures(1, &heat);
glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, heat);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
float heatColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, heatColor);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
heatValuesPsudoTexture = new unsigned char[SCREEN_HEIGHT*SCREEN_WIDTH];
memset(heatValuesPsudoTexture, 255, sizeof(unsigned char)*SCREEN_HEIGHT*SCREEN_WIDTH);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCREEN_WIDTH*SCREEN_HEIGHT, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, &heatValuesPsudoTexture);
heatValuesTexID = GL_TEXTURE2;
pigObj.objloader("Pig/pig.obj");
pigObj.id_texture = GL_TEXTURE1; //https://gamedev.stackexchange.com/questions/144828/why-is-my-texture-not-applied-correctly-in-opengl-2-0-with-glsl
extern NA_MathsLib na_maths;
na_maths.seedDice();
}