Sign in to follow this  
PinguinDude

MD2, Lighting, Normalizing.

Recommended Posts

Hello all, I hope you're doing fine :) Because I am having a small problem ;) First, my normalization code wasn't working correctly. For anyone interested I posted some new code that DOES work. Now, my true problem is that cel shading isn't working exactly. Read below for further details. md2object.cpp
/* ==== md2object.cpp ========================================================
 * Copyright (c) 2007, Led Engine Project.
 *     All rights reserved.
 * ===========================================================================
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of the project nor the names of its contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/* == Description ============================================================
 * The Engine singleton class. Wraps around all subsystems in 1 single class.
 */

/* == Notes ==================================================================
 * SubRender is the actual render function, it is used to allow special effects.
 */

// System headers.
#include <windows.h>
#include <gl/gl.h>
#include <gl/glut.h>

// Engine headers.
#include "common.h"
#include "system.h"

using namespace Led::System;
using namespace Led::Math;

/// Constructor. Initializes the object class.
MD2Object::MD2Object()
{
	// Make sure the texture is NULL.
	gltexture = NULL;
	glshader = NULL;
}

/// Destructor. Destroys the object class.
MD2Object::~MD2Object()
{

}

/// Load. Loads the model.
/// @param string filename the path to the file.
int MD2Object::Load(std::string filename)
{
	std::string imagefile;
	snorm *norms = NULL;
	FILE *file = fopen(filename.c_str(), "rb");

	// Couldn't find the model file.
	if (!file)
	{	
		engine->GetLogger()->Log(Led::System::error, std::string("Couldn't load md2 model:") + filename);

		return 0; // Error.
	}

	// Read in the header and check if the file version corresponds to the one we want to load.
	fread(&header, sizeof(md2_header_t), 1, file);

	if ((header.ident != 844121161) || (header.version != 8))
	{
		engine->GetLogger()->Log(Led::System::error, std::string("MD2 File version is incorrect: ") + filename);

		// Stop reading the file.
		fclose(file);

		return 0; // Error.
	}

	// Allocate memory.
	skins = new md2_skin_t[header.num_skins];
	texcoords = new md2_texcoord_t[header.num_st];
	triangles = new md2_triangle_t[header.num_tris];
	frames = new md2_frame_t[header.num_frames];
	glcommands = new int[header.num_glcmds];

	// Read in model data.
	fseek(file, header.offset_skin, SEEK_SET);
	fread(skins, header.num_skins, sizeof(md2_skin_t), file);

	fseek(file, header.offset_st, SEEK_SET);
	fread(texcoords, header.num_st, sizeof(md2_texcoord_t), file);

	fseek(file, header.offset_tris, SEEK_SET);
	fread(triangles, header.num_tris, sizeof(md2_triangle_t), file);

	fseek(file, header.offset_glcmds, SEEK_SET);
	fread(glcommands, header.num_skins, sizeof(int), file);

	// Read in frames.
	fseek(file, header.offset_frames, SEEK_SET);
	for (int i = 0; i < header.num_frames; i++)
	{
		// Allocate vertices.
		frames[i].verts = new md2_vertex_t[header.num_vertices];
	
		// Allocate normals.
		frames[i].normals = new vec3_t[header.num_tris];

		// Read in data.
		fread(frames[i].scale, 1, sizeof(vec3_t), file);
		fread(frames[i].translate, 1, sizeof(vec3_t), file);
		fread(frames[i].name, 16, sizeof(char), file);
		fread(frames[i].verts, header.num_vertices, sizeof (md2_vertex_t), file);
	}

	// Close the file, we're done reading.
	fclose(file);

	/*
	Normal calculation. The most messy and complicated part of it all.
	*/
	for (int i = 0; i < header.num_frames; i++)
	{
		norms = new snorm[header.num_vertices];

		for (int j = 0; j < header.num_tris; j++)
		{
			md2_vertex_t *vertex1 = &frames[0].verts[triangles[j].vertex[0]];
			md2_vertex_t *vertex2 = &frames[0].verts[triangles[j].vertex[1]];
			md2_vertex_t *vertex3 = &frames[0].verts[triangles[j].vertex[2]];

			Vector p1 = Vector(vertex1->v[0], vertex1->v[1], vertex1->v[2], 1);
			Vector p2 = Vector(vertex2->v[0], vertex2->v[1], vertex2->v[2], 1);
			Vector p3 = Vector(vertex3->v[0], vertex3->v[1], vertex3->v[2], 1);

			Vector v1 = p1 - p2;
			Vector v2 = p1 - p3;
			Vector normal = v1.CrossProduct(v2);
					
			normal.Normalize();

			norms[triangles[j].vertex[0]].sum_normals = normal;
			norms[triangles[j].vertex[0]].normals ++;
			norms[triangles[j].vertex[1]].sum_normals = normal;
			norms[triangles[j].vertex[1]].normals ++;
			norms[triangles[j].vertex[2]].sum_normals = normal;
			norms[triangles[j].vertex[2]].normals ++;
		}

		for (int k = 0; k < header.num_vertices; k++)
		{
			frames[i].normals[i][0] = norms[k].sum_normals.GetX() / norms[k].normals;
			frames[i].normals[i][1] = norms[k].sum_normals.GetY() / norms[k].normals;
			frames[i].normals[i][2] = norms[k].sum_normals.GetZ() / norms[k].normals;
		}

		// Not required anymore.
		delete norms;
	}

	return 1;
}

/// Update. Updates the object ( Animations etc. )
int MD2Object::Update()
{
	frametime_t *timer = engine->GetTimer();
	float curtime = timer->curframe * 0.01f;

	// Did the interpolation for this frame finish ?
	if (curtime - oldtime > (1.0f / fps))
	{
		// Move on to the next frame.
		curframe = nextframe;
		nextframe++;

		// Reset for smooth animation.
		if (nextframe > endframe)
			nextframe = startframe;

		// Store the last time.
		oldtime = curtime;
	}

	// Make sure we don't go out of bounds.
	if (curframe > header.num_frames - 1)
		curframe = 0;

	if (nextframe > header.num_frames - 1)
		nextframe = 0;

	// Calculate interpolation value.
	interp = fps * (curtime - oldtime);

	return 0;
}

/// Render. Renders the object.
int MD2Object::Render()
{
	if (curframe < 0 || curframe > header.num_frames - 1)
		return 0; // Bad frame.

	if (!gltexture)
		return 0; // No valid texture. Stop rendering.

	// Start rendering.
	glPushMatrix();

	// Position.
	glTranslatef(position.GetX(), position.GetY(), position.GetZ());
	glRotatef(rotation.GetX() - -90.0f, 1, 0, 0);
	glRotatef(rotation.GetY() - 180, 0, 1, 0);
	glRotatef(rotation.GetZ() - -90.0f, 0, 0, 1);

	// Bind the texture.
	gltexture->BindTexture();

	// Check for effects.
	switch(gleffect)
	{
	case effect_outline:
			// Push the GL attribute bits so that we don't wreck any settings
			glPushAttrib( GL_ALL_ATTRIB_BITS );
			// Enable polygon offsets, and offset filled polygons forward by 2.5
			glEnable( GL_POLYGON_OFFSET_FILL );
			glPolygonOffset( -2.5f, -2.5f );
			// Set the render mode to be line rendering with a thick line width
			glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
			glLineWidth( 4.0f );
			// Set the colour to be white
			glColor3f( 0.0f, 0.0f, 0.0f );

			SubRender();

			// Set the polygon mode to be filled triangles 
			glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
			//glEnable( GL_LIGHTING );
			// Set the colour to the background
			glColor3f( 1.0f, 1.0f, 1.0f );
		break;
	default:
		break;
	}

	// Enable a shader if we have one.
	if (glshader)
		glshader->Bind();


	SubRender();
	
	// Pop the state changes off the attribute stack
	// to set things back how they were
	glPopAttrib();

	if (glshader)
		glshader->UnBind();

	gltexture->UnBindTexture();

	// Done rendering.
	glPopMatrix();

	return 1;
}

/// SubRender. TRUELY Render the model.
int MD2Object::SubRender()
{
	GLfloat s, t;
	vec3_t v, v_current, v_next, n, n_current, n_next, *normals, *normals_next;
	md2_frame_t *frame;
	md2_frame_t *frame_next;
	md2_vertex_t *vertex;
	md2_vertex_t *vertex_next;

	glBegin(GL_TRIANGLES);
		for (int i = 0; i < header.num_tris; ++i)
		{
			for (int j = 0; j < 3; ++j)
			{
				// Get the pointers.
				frame = &frames[curframe];
				frame_next = &frames[nextframe];
				vertex = &frame->verts[triangles[i].vertex[j]];
				vertex_next = &frame_next->verts[triangles[i].vertex[j]];
				
				// Catch normals.
				normals = &frames[0].normals[triangles[i].vertex[j]];
				normals_next = &frame_next->normals[triangles[i].vertex[j]];


				// Calculate texture coordinates.
				s = (GLfloat)texcoords[triangles[i].st[j]].s / header.skinwidth;
				t = (GLfloat)texcoords[triangles[i].st[j]].t / header.skinheight;

				// Render the model.
				glTexCoord2f(s, t);
				
				// Interpolate normals.
			/*	n_current[0] = frame->scale[0] * *normals[0] + frame->translate[0];
				n_current[1] = frame->scale[1] * *normals[1] + frame->translate[1];
				n_current[2] = frame->scale[2] * *normals[2] + frame->translate[2];

				n_next[0] = frame_next->scale[0] * *normals_next[0] + frame_next->translate[0];
				n_next[1] = frame_next->scale[1] * *normals_next[1] + frame_next->translate[1];
				n_next[2] = frame_next->scale[2] * *normals_next[2] + frame_next->translate[2];

				n[0] = n_current[0] + interp * (n_next[0] - n_current[0]);
				n[1] = n_current[1] + interp * (n_next[1] - n_current[1]);
				n[2] = n_current[2] + interp * (n_next[2] - n_current[2]);*/

				// Interpolate vertices.
				v_current[0] = frame->scale[0] * vertex->v[0] + frame->translate[0];
				v_current[1] = frame->scale[1] * vertex->v[1] + frame->translate[1];
				v_current[2] = frame->scale[2] * vertex->v[2] + frame->translate[2];

				v_next[0] = frame_next->scale[0] * vertex_next->v[0] + frame_next->translate[0];
				v_next[1] = frame_next->scale[1] * vertex_next->v[1] + frame_next->translate[1];
				v_next[2] = frame_next->scale[2] * vertex_next->v[2] + frame_next->translate[2];

				v[0] = v_current[0] + interp * (v_next[0] - v_current[0]);
				v[1] = v_current[1] + interp * (v_next[1] - v_current[1]);
				v[2] = v_current[2] + interp * (v_next[2] - v_current[2]);
				
				glNormal3fv(*normals);
				glVertex3fv(v);
			}
		}
	glEnd();

	return 0;
}
/// Destroy. Destroys the object.
int MD2Object::Destroy()
{
	if (gltexture)
	{
		gltexture->Destroy();
		delete gltexture;

		gltexture = NULL;
	}

	delete skins;
	delete texcoords;
	delete triangles;
	delete frames->normals;
	delete frames->verts;
	delete frames;
	delete glcommands;

	return 0;
}

/// SetAnimation. Sets the animation frames.
/// @param int start the starting frame.
/// @param int end the ending frame.
/// @param float fps the frames per second.
int MD2Object::SetAnimation(int start, int end, float framefps)
{
	nextframe = start;
	startframe = start;
	endframe = end;
	fps = framefps;

	return 0;
}

/// SetTexture. Sets the texture of the object.
/// @param Texture2D texture a pointer to the texture object.
int MD2Object::SetTexture(Texture2D *texture)
{
	gltexture = texture;

	return 0;
}

/// SetEffect. Allows you to specify a model effect, outlining etc.
/// @param int effect the effect.
int MD2Object::SetEffect(int effect)
{
	gleffect = effect;

	return 0;
}

/// SetShader. Sets the current shader of the object.
/// @param BaseShader shader a pointer to the shader object.
int MD2Object::SetShader(BaseShader *shader)
{
	glshader = shader;

	return 0;
}

/// SetPosition. Sets the position of the object in the scene.
/// @param vector vector determines the position.
int MD2Object::SetPosition(Led::Math::Vector &vector)
{
	position = vector;

	return 0;
}

// SetRotation. Sets the rotation of the object in the scene.
/// @param vector vector determines the position.
int MD2Object::SetRotation(Led::Math::Vector &vector)
{
	rotation = vector;

	return 0;
}

/// GetPosition. Returns a reference to the object's position.
const Vector &MD2Object::GetPosition() const
{
	return position;
}

/// GetRotation. Returns a reference to the object's rotation.
const Vector &MD2Object::GetRotation() const
{
	return rotation;
}

Any information, tip, etc would be nice :)! Thank you. [Edited by - PinguinDude on April 9, 2007 2:54:33 PM]

Share this post


Link to post
Share on other sites
Though it may not be of any help, this is my code, it seems to work.



typedef struct avector{
float x,y,z,nx,ny,nz;
} avector;

typedef struct animframe{
avector * vers;
char name[16];
} animframe;

typedef struct poly{
short verindex[3];
short texindex[3];
} poly;


typedef struct anim{
int numframes;
int numvers;
int numpolys;

poly *polys;
uv *uvs;

animframe *frames;

} anim;

typedef unsigned char md2vertex[3];

typedef struct md2point{
unsigned char triple[3];
unsigned char lightindexnormal;
} md2point;

typedef struct md2texcoord{
short u;
short v;
} md2texcoord;


typedef struct md2frame{
float scale[3];
float trans[3];
char name[16];

md2point vers[1];
} md2frame;



typedef struct md2header{
int id;
int version;

int texw;
int texh;
int framesize;

int numskins;
int numvers;
int numtex;
int numpolys;
int numcmds;
int numframes;

int skinoffset;
int texcoordoffset;
int polyoffset;
int frameoffset;
int cmdoffset;
int endoffset;
} md2header;


void normalize(avector * v){
float d=(float)sqrt(v->nx*v->nx+v->ny*v->ny+v->nz*v->nz);
if(d!=0){
v->nx/=d;
v->ny/=d;
v->nz/=d;
}
}


int loadanim(anim * a, char * filename){
md2header header;
md2frame * frame;
char * buffer;

FILE *file=NULL;

if(!(file=fopen(filename,"rb"))){
return(1);
}

fread(&header,sizeof(md2header),1,file);

a->numframes=header.numframes;//set the num of frAMES in the a to the num loaded
a->numvers=header.numvers;
a->numpolys=header.numpolys;

a->frames=(animframe *)malloc(sizeof(animframe)*header.numframes);


buffer=(char *)malloc(header.numframes*header.framesize);

fseek(file,header.frameoffset,SEEK_SET);
fread(buffer,header.framesize,header.numframes,file);

for(int indexf=0;indexf<header.numframes;indexf++){
a->frames[indexf].vers=(avector *)malloc(sizeof(avector)*header.numvers);

frame=(md2frame *)&buffer[header.framesize*indexf];

strcpy(a->frames[indexf].name,frame->name);
for(int indexv=0;indexv<header.numvers;indexv++){
a->frames[indexf].vers[indexv].x=(((float)frame->vers[indexv].triple[0]*frame->scale[0])+frame->trans[0]);
a->frames[indexf].vers[indexv].z=(((float)frame->vers[indexv].triple[1]*frame->scale[1])+frame->trans[1]);
a->frames[indexf].vers[indexv].y=(((float)frame->vers[indexv].triple[2]*frame->scale[2])+frame->trans[2]);
}
}

if(buffer){
free(buffer);
}


char str[1000];

a->uvs=(uv *)malloc(sizeof(uv)*header.numtex);

short uvcoord=0;

fseek(file,header.texcoordoffset,SEEK_SET);
for(int index=0;index<header.numtex;index++){
fread(&uvcoord,sizeof(short),1,file);
a->uvs[index].u=(float)uvcoord/(float)header.texw;
fread(&uvcoord,sizeof(short),1,file);
a->uvs[index].v=-1.0f*((float)uvcoord/(float)header.texh);
}

a->polys=(poly *)malloc(sizeof(poly)*header.numpolys);
fseek(file,header.polyoffset,SEEK_SET);
for(int indexp=0;indexp<header.numpolys;indexp++){
fread(&(a->polys[indexp]),sizeof(poly),1,file);
}
//fread(&(a->polys),sizeof(poly)*header.numpolys,1,file);

fclose(file);

for(int findex=0;findex<a->numframes;findex++){
for(int vindex=0;vindex<a->numvers;vindex++){
a->frames[findex].vers[vindex].nx=0;
a->frames[findex].vers[vindex].ny=0;
a->frames[findex].vers[vindex].nz=0;
}
for(int tindex=0;tindex<a->numpolys;tindex++){
float nchunk[3];
normalchunk(a,tindex,findex,nchunk);
for(int temp=0;temp<3;temp++){
a->frames[findex].vers[a->polys[tindex].verindex[temp]].nx-=nchunk[0];
a->frames[findex].vers[a->polys[tindex].verindex[temp]].ny+=nchunk[2];
a->frames[findex].vers[a->polys[tindex].verindex[temp]].nz-=nchunk[1];
/*a->frames[findex].vers[a->polys[tindex].verindex[temp]].nx+=nchunk[0];
a->frames[findex].vers[a->polys[tindex].verindex[temp]].ny+=nchunk[1];
a->frames[findex].vers[a->polys[tindex].verindex[temp]].nz+=nchunk[2];*/

}
}
for(int vindex=0;vindex<a->numvers;vindex++)
normalize(&(a->frames[findex].vers[vindex]));
}


return(0);
}






[Edited by - Th0ughtCr1me on April 7, 2007 8:14:10 PM]

Share this post


Link to post
Share on other sites
Vector v1 = p2 - p1;
Vector v2 = p3 - p1;

Try this

Vector v1 = p1 - p2;
Vector v2 = p2 - p3;

and I don't see any code for the normalize() or cross product. I am not sure what those look like either....

Share this post


Link to post
Share on other sites
Well, I managed to fix the normalization code after 1000 retries. I'll upload the new code. So, another problem pops up. I am trying to write a cel shader. It however doesn't seem to work exactly well ( I am very new to glsl ).

celshader.cpp

/* ==== baseobject.h =========================================================
* Copyright (c) 2007, Plastic Engine Project
* All rights reserved.
* ===========================================================================
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/


/* == Description ============================================================
* CelShader. Cell Shades the currently rendered object.
*/


/* == Notes ==================================================================
*
*/


// System headers
#include <windows.h>
#include <sdl/sdl.h>
#include <gl/glew.h>
#include <gl/gl.h>

// Engine headers
#include "common.h"
#include "system.h"

using namespace Led::System;
using namespace Led::Math;

/// CelShader. Constructor.
CelShader::CelShader()
{

}

/// Load. Loads the shader, and calls compile.
/// @param string filename the path to the file.
int CelShader::Load(std::string filename)
{
std::string s_frag_file = filename + ".frag";
std::string s_vert_file = filename + ".vert";

// Load in the fragment shader string.
std::ifstream frag_file(s_frag_file.c_str());

if (frag_file.is_open())
{
while (!frag_file.eof())
{
std::string line;
getline(frag_file, line);

s_fragment += line;
}
}

frag_file.close();

// Load in vertex shader string.
std::ifstream vert_file(s_vert_file.c_str());

if (vert_file.is_open())
{
while (!vert_file.eof())
{
std::string line;
getline(vert_file, line);

s_vertex += line;
}
}

vert_file.close();

// Compile !.
Compile();

return 0;
}

/// Compile. Compiles the shader.
int CelShader::Compile()
{
const char *c_vertex = s_vertex.c_str();
GLint c_vertex_len = s_vertex.length();
const char *c_fragment = s_fragment.c_str();
GLint c_fragment_len = s_fragment.length();
GLint retval = GL_TRUE;

// Create the shader.
glsl_vertex = glCreateShader(GL_VERTEX_SHADER);
glsl_fragment = glCreateShader(GL_FRAGMENT_SHADER);

// Assign data.
glShaderSource(glsl_vertex, 1, &c_vertex, &c_vertex_len);

// Compile the shader.
glCompileShader(glsl_vertex);

//
// test for errors here.
//
glGetShaderiv(glsl_vertex, GL_COMPILE_STATUS, &retval);

if (retval != GL_TRUE)
{
engine->GetLogger()->Log(System::message, "Couldn't compile VertexShader: CelShader");
engine->GetLogger()->Log(System::message, s_vertex);
}

// Assign data.
glShaderSource(glsl_fragment, 1, &c_fragment, &c_fragment_len);

// Compile the shader.
glCompileShader(glsl_fragment);

//
// test for errors here.
//
glGetShaderiv(glsl_fragment, GL_COMPILE_STATUS, &retval);

if (retval != GL_TRUE)
{
engine->GetLogger()->Log(System::message, "Couldn't compile FragmentShader: CelShader");
engine->GetLogger()->Log(System::message, s_fragment);
}

// Create the program.
glsl_program = glCreateProgram();

// Link shaders into the program.
glAttachShader(glsl_program, glsl_vertex);
glAttachShader(glsl_program, glsl_fragment);

// Link the program.
glLinkProgram(glsl_program);

// Create a 1D toon texture.
float pixels[16] = {0.4f, 0.4f, 0.4f, 0.4f, 0.5f, 0.5f, 0.5f, 0.5f, 0.7f, 0.7f, 0.7f, 0.8f, 0.9f, 1.0f, 1.0f, 1.0f};
//float pixels[16] = {1.0f, 1.0f, 1.0f, 1.0f, 0.9f, 0.8f, 0.8f, 0.7f, 0.7f, 0.5f, 0.5f, 0.4f, 0.4f, 0.4f, 0.4f, 0.4f};

glGenTextures(1, (GLuint*)&tex[0]);
glBindTexture(GL_TEXTURE_1D, tex[0]);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 16, 0, GL_LUMINANCE, GL_FLOAT, pixels);

return 0;
}

/// Set functions.
/// @param Vector vector the new value.
/// @param string name the name of the var.
int CelShader::SetVector3(Vector vector, std::string name)
{
int var = glGetUniformLocation(glsl_program, name.c_str());
glUniform3f(var, vector.GetX(), vector.GetY(), vector.GetZ());

return 0;
}
int CelShader::SetVector4(Vector vector, std::string name)
{
int var = glGetUniformLocation(glsl_program, name.c_str());
glUniform4f(var, vector.GetX(), vector.GetY(), vector.GetZ(), vector.GetW());

return 0;
}

/// Bind. Activates the current shader.
int CelShader::Bind()
{
int celtexture = 0;
int realtexture = 0;

// Use our shader.
glUseProgram(glsl_program);

// Retrieve texture acces.
celtexture = glGetUniformLocation(glsl_program, "celtex");
realtexture = glGetUniformLocation(glsl_program, "realtex");

// Tell it that the cell shade texture is on layer 2, normal texture on layer 1.
glActiveTexture(GL_TEXTURE1);
glUniform1i(celtexture, 1);
glBindTexture(GL_TEXTURE_1D, tex[0]);

glActiveTexture(GL_TEXTURE0);
glUniform1i(realtexture, 0);

return 0;
}

/// UnBind. UnBinds the shader.
int CelShader::UnBind()
{
glUseProgram(0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_1D, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);

return 0;
}



cel.vert

varying vec3 lightdir, normal;
uniform sampler1D celtex;
uniform sampler2D realtex;

void main()
{
normal = gl_NormalMatrix * gl_Normal;

gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = ftransform();
}



cel.frag

varying vec3 lightdir, normal;
uniform sampler1D celtex;
uniform sampler2D realtex;

void main()
{
vec3 n = normalize(normal);
int light = dot(vec3(normalize(lightdir)),n) * 15;

gl_FragColor = texture2D(realtex, gl_TexCoord[0].st) * texture1D(celtex, gl_TexCoord[0].st + light);
}



And the result,

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this