Jump to content
  • Advertisement
Sign in to follow this  
PinguinDude

MD2, Lighting, Normalizing.

This topic is 4088 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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.verts = new md2_vertex_t[header.num_vertices];
	
		// Allocate normals.
		frames.normals = new vec3_t[header.num_tris];

		// Read in data.
		fread(frames.scale, 1, sizeof(vec3_t), file);
		fread(frames.translate, 1, sizeof(vec3_t), file);
		fread(frames.name, 16, sizeof(char), file);
		fread(frames.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.normals[0] = norms[k].sum_normals.GetX() / norms[k].normals;
			frames.normals[1] = norms[k].sum_normals.GetY() / norms[k].normals;
			frames.normals[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.vertex[j]];
				vertex_next = &frame_next->verts[triangles.vertex[j]];
				
				// Catch normals.
				normals = &frames[0].normals[triangles.vertex[j]];
				normals_next = &frame_next->normals[triangles.vertex[j]];


				// Calculate texture coordinates.
				s = (GLfloat)texcoords[triangles.st[j]].s / header.skinwidth;
				t = (GLfloat)texcoords[triangles.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
Advertisement
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
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!