Initial version with smooth blending!

This commit is contained in:
David Williams 2007-08-15 23:03:23 +00:00
parent 6e21e971fc
commit 48094c972a
6 changed files with 447 additions and 66 deletions

82
include/Vertex.h Normal file
View File

@ -0,0 +1,82 @@
/******************************************************************************
This file is part of a voxel plugin for OGRE
Copyright (C) 2006 David Williams
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
******************************************************************************/
#ifndef __Vertex_H__
#define __Vertex_H__
#include "OgrePrerequisites.h"
#include "OgreVector3.h"
#include "OgreVector4.h"
namespace Ogre
{
class Vertex
{
public:
Vector3 position;
Vector3 normal;
Vector4 colour;
Vertex(Vector3 positionToSet)
:position(positionToSet)
{
}
Vertex(Vector3 positionToSet, Vector3 normalToSet)
:position(positionToSet)
,normal(normalToSet)
{
}
bool matchesPosition(const Vector3& rhs) const
{
//return ((x == rhs.x) && (y == rhs.y) && (z == rhs.z));
return ((position - rhs).length() < 0.01);
}
/*bool operator < (const Vertex& rhs) const
{
if(z < rhs.z)
{
return true;
}
else
{
if(y < rhs.y)
{
return true;
}
else
{
if(x < rhs.x)
{
return true;
}
else
{
return false;
}
}
}
}*/
};
}
#endif

View File

@ -0,0 +1,22 @@
struct v2f
{
float4 Position : POSITION; //in projection space
float4 Color : COLOR;
float4 TexCoordsXY : TEXCOORD0;
float4 TexCoordsYZ : TEXCOORD1;
float4 TexCoordsXZ : TEXCOORD2;
float4 Normal : TEXCOORD3;
};
float4 main(v2f IN, uniform sampler2D colourMap : TEXUNIT0) : COLOR
{
float3 colourMapValueXY = tex2D(colourMap, IN.TexCoordsXY.xy).rgb * abs(IN.Normal.z);
float3 colourMapValueYZ = tex2D(colourMap, IN.TexCoordsYZ.xy).rgb * abs(IN.Normal.x);
float3 colourMapValueXZ = tex2D(colourMap, IN.TexCoordsXZ.xy).rgb * abs(IN.Normal.y);
float3 colourMapValue = colourMapValueXY + colourMapValueYZ + colourMapValueXZ;
//colourMapValue /= 3.0;
return float4(colourMapValue/*IN.Color.rgb*/, pow(IN.Color.a,0.75));
}

View File

@ -0,0 +1,145 @@
//NOTE - The code in this file might seem slightly strange. Intuitivy it would
//seem better to get Ogre to pass in an array of lights, rather than passing
//them individually and then building arrays. However, I have had problms with
//this approach (possibly a bug?)
//See http://www.ogre3d.org/phpBB2/viewtopic.php?t=32391
struct a2v
{
float4 Position : POSITION; //in object space
float3 Normal : NORMAL;
float4 Color : COLOR;
};
struct v2f
{
float4 Position : POSITION; //in projection space
float4 Color : COLOR;
float4 TexCoordsXY : TEXCOORD0;
float4 TexCoordsYZ : TEXCOORD1;
float4 TexCoordsXZ : TEXCOORD2;
float4 Normal : TEXCOORD3;
};
struct light
{
float4 position;
float4 diffuseColour;
float4 attenuation;
};
v2f doWork(a2v IN, float4x4 world, float4x4 viewProj, float textureScale, float4 ambient, int iNoOfLights, light lights[4])
{
v2f OUT;
OUT.Position = mul(world, IN.Position);
float3 uVec;
float3 vVec;
IN.Normal = normalize(IN.Normal);
/*float absX = abs(IN.Normal.x);
float absY = abs(IN.Normal.y);
float absZ = abs(IN.Normal.z);
if((absZ <= absX) && (absZ <= absY))
{
//OUT.TexCoords.xy = OUT.Position.xy /textureScale;
uVec = float3(-IN.Normal.y, IN.Normal.x,0);
}
else if((absY <= absX) && (absY <= absZ))
{
//OUT.TexCoords.xy = OUT.Position.xz /textureScale;
uVec = float3(-IN.Normal.z, 0, IN.Normal.x);
}
else if((absX <= absZ) && (absX <= absY))
{
// OUT.TexCoords.xy = OUT.Position.yz /textureScale;
uVec = float3(0, -IN.Normal.z, IN.Normal.y);
}
vVec = cross(IN.Normal, uVec);
OUT.TexCoords.x = dot(OUT.Position.xyz, uVec);
OUT.TexCoords.y = dot(OUT.Position.xyz, vVec); */
//OUT.TexCoords.xy = OUT.Position.xy * IN.Normal.z * IN.Normal.z + OUT.Position.xz * IN.Normal.y * IN.Normal.y + OUT.Position.yz * IN.Normal.x * IN.Normal.x;
//OUT.TexCoords.xy /= textureScale;
OUT.TexCoordsXY.xy = OUT.Position.xy;
OUT.TexCoordsYZ.xy = OUT.Position.yz;
OUT.TexCoordsXZ.xy = OUT.Position.xz;
OUT.TexCoordsXY.xy /= textureScale;
OUT.TexCoordsYZ.xy /= textureScale;
OUT.TexCoordsXZ.xy /= textureScale;
OUT.Normal = float4(IN.Normal,0.0);
//OUT.TexCoords.xy = OUT.Position.yz /textureScale;
OUT.TexCoordsXY.w = 1;
OUT.TexCoordsYZ.w = 1;
OUT.TexCoordsXZ.w = 1;
OUT.Color.rgba = float4(0.0,0.0,0.0,1.0);
for(int lightCt = 0; lightCt < iNoOfLights; lightCt++)
{
float3 L = normalize(lights[lightCt].position.xyz - OUT.Position.xyz);
//Calculate attenuation factor.
float d = distance(lights[lightCt].position.xyz, OUT.Position.xyz);
float attenuationFactor = 1.0 / (lights[lightCt].attenuation.y + lights[lightCt].attenuation.z * d + lights[lightCt].attenuation.w * d * d);
// Calculate diffuse component
float LdotN = max(dot(L, IN.Normal) , 0);
OUT.Color.rgb += lights[lightCt].diffuseColour.rgb * LdotN * attenuationFactor;
}
OUT.Color.rgb += ambient.rgb;
//Temporary
OUT.Color = IN.Color;
OUT.Position = mul(viewProj, OUT.Position);
return OUT;
}
v2f OneLight(a2v IN,uniform float4x4 world, uniform float4x4 viewProj, uniform float textureScale, uniform float4 ambient, uniform light light0)
{
light lights[4];
lights[0] = light0;
return doWork(IN, world, viewProj, textureScale, ambient, 1, lights);
}
v2f TwoLights(a2v IN,uniform float4x4 world, uniform float4x4 viewProj, uniform float textureScale, uniform float4 ambient, uniform light light0, uniform light light1)
{
light lights[4];
lights[0] = light0;
lights[1] = light1;
return doWork(IN, world, viewProj, textureScale, ambient, 2, lights);
}
v2f ThreeLights(a2v IN,uniform float4x4 world, uniform float4x4 viewProj, uniform float textureScale, uniform float4 ambient, uniform light light0, uniform light light1, uniform light light2)
{
light lights[4];
lights[0] = light0;
lights[1] = light1;
lights[2] = light2;
return doWork(IN, world, viewProj, textureScale, ambient, 3, lights);
}
v2f FourLights(a2v IN,uniform float4x4 world, uniform float4x4 viewProj, uniform float textureScale, uniform float4 ambient, uniform light light0, uniform light light1, uniform light light2, uniform light light3)
{
light lights[4];
lights[0] = light0;
lights[1] = light1;
lights[2] = light2;
lights[3] = light3;
return doWork(IN, world, viewProj, textureScale, ambient, 4, lights);
}

View File

@ -588,6 +588,7 @@ namespace Ogre
const Vector3 offset(firstX,firstY,firstZ);
Vector3 vertlist[12];
uchar vertMaterials[12];
VolumeIterator volIter(*volumeData);
volIter.setValidRegion(firstX,firstY,firstZ,lastX,lastY,lastZ);
@ -639,72 +640,84 @@ namespace Ogre
vertlist[0].x = (static_cast<double>(x) + 0.5);
vertlist[0].y = (static_cast<double>(y));
vertlist[0].z = (static_cast<double>(z));
vertMaterials[0] = (std::max)(v000,v100); //FIXME - faster way?
}
if (edgeTable[iCubeIndex] & 2)
{
vertlist[1].x = (static_cast<double>(x + 1));
vertlist[1].y = (static_cast<double>(y) + 0.5);
vertlist[1].z = (static_cast<double>(z));
vertMaterials[1] = (std::max)(v100,v110);
}
if (edgeTable[iCubeIndex] & 4)
{
vertlist[2].x = (static_cast<double>(x) + 0.5);
vertlist[2].y = (static_cast<double>(y + 1));
vertlist[2].z = (static_cast<double>(z));
vertMaterials[2] = (std::max)(v010,v110);
}
if (edgeTable[iCubeIndex] & 8)
{
vertlist[3].x = (static_cast<double>(x));
vertlist[3].y = (static_cast<double>(y) + 0.5);
vertlist[3].z = (static_cast<double>(z));
vertMaterials[3] = (std::max)(v000,v010);
}
if (edgeTable[iCubeIndex] & 16)
{
vertlist[4].x = (static_cast<double>(x) + 0.5);
vertlist[4].y = (static_cast<double>(y));
vertlist[4].z = (static_cast<double>(z + 1));
vertMaterials[4] = (std::max)(v001,v101);
}
if (edgeTable[iCubeIndex] & 32)
{
vertlist[5].x = (static_cast<double>(x + 1));
vertlist[5].y = (static_cast<double>(y) + 0.5);
vertlist[5].z = (static_cast<double>(z + 1));
vertMaterials[5] = (std::max)(v101,v111);
}
if (edgeTable[iCubeIndex] & 64)
{
vertlist[6].x = (static_cast<double>(x) + 0.5);
vertlist[6].y = (static_cast<double>(y + 1));
vertlist[6].z = (static_cast<double>(z + 1));
vertMaterials[6] = (std::max)(v011,v111);
}
if (edgeTable[iCubeIndex] & 128)
{
vertlist[7].x = (static_cast<double>(x));
vertlist[7].y = (static_cast<double>(y) + 0.5);
vertlist[7].z = (static_cast<double>(z + 1));
vertMaterials[7] = (std::max)(v001,v011);
}
if (edgeTable[iCubeIndex] & 256)
{
vertlist[8].x = (static_cast<double>(x));
vertlist[8].y = (static_cast<double>(y));
vertlist[8].z = (static_cast<double>(z) + 0.5);
vertMaterials[8] = (std::max)(v000,v001);
}
if (edgeTable[iCubeIndex] & 512)
{
vertlist[9].x = (static_cast<double>(x + 1));
vertlist[9].y = (static_cast<double>(y));
vertlist[9].z = (static_cast<double>(z) + 0.5);
vertMaterials[9] = (std::max)(v100,v101);
}
if (edgeTable[iCubeIndex] & 1024)
{
vertlist[10].x = (static_cast<double>(x + 1));
vertlist[10].y = (static_cast<double>(y + 1));
vertlist[10].z = (static_cast<double>(z) + 0.5);
vertMaterials[10] = (std::max)(v110,v111);
}
if (edgeTable[iCubeIndex] & 2048)
{
vertlist[11].x = (static_cast<double>(x));
vertlist[11].y = (static_cast<double>(y + 1));
vertlist[11].z = (static_cast<double>(z) + 0.5);
vertMaterials[11] = (std::max)(v010,v011);
}
for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3)
@ -714,15 +727,24 @@ namespace Ogre
const Vector3 vertex1 = vertlist[triTable[iCubeIndex][i+1]] - offset;
const Vector3 vertex2 = vertlist[triTable[iCubeIndex][i+2]] - offset;
const uchar material0 = vertMaterials[triTable[iCubeIndex][i ]];
const uchar material1 = vertMaterials[triTable[iCubeIndex][i+1]];
const uchar material2 = vertMaterials[triTable[iCubeIndex][i+2]];
//FIXME - for the time being the material is the highest vertex
//Need to think about this...
uchar material = std::max(v000,v001);
/*uchar material = std::max(v000,v001);
material = std::max(material,v010);
material = std::max(material,v011);
material = std::max(material,v100);
material = std::max(material,v101);
material = std::max(material,v110);
material = std::max(material,v111);
material = std::max(material,v111); */
std::set<uchar> materials; //FIXME - set::set is pretty slow for this as it only holds up to 3 vertices.
materials.insert(material0);
materials.insert(material1);
materials.insert(material2);
//vertexScaled values are always integers and so can be used as indices.
//FIXME - these integer values can just be obtained by using floor()?
@ -733,74 +755,94 @@ namespace Ogre
Triangle triangle; //Triangle to be created...
//Get scaled values for vertex 0
vertexScaledX = static_cast<unsigned int>((vertex0.x * 2.0) + 0.5);
vertexScaledY = static_cast<unsigned int>((vertex0.y * 2.0) + 0.5);
vertexScaledZ = static_cast<unsigned int>((vertex0.z * 2.0) + 0.5);
vertexScaledX %= OGRE_REGION_SIDE_LENGTH*2+1;
vertexScaledY %= OGRE_REGION_SIDE_LENGTH*2+1;
vertexScaledZ %= OGRE_REGION_SIDE_LENGTH*2+1;
//If a vertex has not yet been added, it's index is -1
index = vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material];
if((index == -1))
for(std::set<uchar>::iterator materialsIter = materials.begin(); materialsIter != materials.end(); ++materialsIter)
{
//Add the vertex
vertexData[material].push_back(Vertex(vertex0));
triangle.v0 = vertexData[material].size()-1;
vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material] = vertexData[material].size()-1;
}
else
{
//Just reuse the existing vertex
triangle.v0 = index;
}
uchar material = *materialsIter;
//Get scaled values for vertex 1
vertexScaledX = static_cast<unsigned int>((vertex1.x * 2.0) + 0.5);
vertexScaledY = static_cast<unsigned int>((vertex1.y * 2.0) + 0.5);
vertexScaledZ = static_cast<unsigned int>((vertex1.z * 2.0) + 0.5);
vertexScaledX %= OGRE_REGION_SIDE_LENGTH*2+1;
vertexScaledY %= OGRE_REGION_SIDE_LENGTH*2+1;
vertexScaledZ %= OGRE_REGION_SIDE_LENGTH*2+1;
//If a vertex has not yet been added, it's index is -1
index = vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material];
if((index == -1))
{
//Add the vertex
vertexData[material].push_back(Vertex(vertex1));
triangle.v1 = vertexData[material].size()-1;
vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material] = vertexData[material].size()-1;
}
else
{
//Just reuse the existing vertex
triangle.v1 = index;
}
//Get scaled values for vertex 0
vertexScaledX = static_cast<unsigned int>((vertex0.x * 2.0) + 0.5);
vertexScaledY = static_cast<unsigned int>((vertex0.y * 2.0) + 0.5);
vertexScaledZ = static_cast<unsigned int>((vertex0.z * 2.0) + 0.5);
vertexScaledX %= OGRE_REGION_SIDE_LENGTH*2+1;
vertexScaledY %= OGRE_REGION_SIDE_LENGTH*2+1;
vertexScaledZ %= OGRE_REGION_SIDE_LENGTH*2+1;
//If a vertex has not yet been added, it's index is -1
index = vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material];
if((index == -1))
{
//Add the vertex
Vertex vertex(vertex0);
if(material0 == material)
vertex.colour = Vector4(1.0,1.0,1.0,1.0);
else
vertex.colour = Vector4(0.0,0.0,0.0,0.0);
vertexData[material].push_back(Vertex(vertex));
triangle.v0 = vertexData[material].size()-1;
vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material] = vertexData[material].size()-1;
}
else
{
//Just reuse the existing vertex
triangle.v0 = index;
}
//Get scaled values for vertex 2
vertexScaledX = static_cast<unsigned int>((vertex2.x * 2.0) + 0.5);
vertexScaledY = static_cast<unsigned int>((vertex2.y * 2.0) + 0.5);
vertexScaledZ = static_cast<unsigned int>((vertex2.z * 2.0) + 0.5);
vertexScaledX %= OGRE_REGION_SIDE_LENGTH*2+1;
vertexScaledY %= OGRE_REGION_SIDE_LENGTH*2+1;
vertexScaledZ %= OGRE_REGION_SIDE_LENGTH*2+1;
//If a vertex has not yet been added, it's index is -1
index = vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material];
if((index == -1))
{
//Add the vertex
vertexData[material].push_back(Vertex(vertex2));
triangle.v2 = vertexData[material].size()-1;
vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material] = vertexData[material].size()-1;
}
else
{
//Just reuse the existing vertex
triangle.v2 = index;
}
//Get scaled values for vertex 1
vertexScaledX = static_cast<unsigned int>((vertex1.x * 2.0) + 0.5);
vertexScaledY = static_cast<unsigned int>((vertex1.y * 2.0) + 0.5);
vertexScaledZ = static_cast<unsigned int>((vertex1.z * 2.0) + 0.5);
vertexScaledX %= OGRE_REGION_SIDE_LENGTH*2+1;
vertexScaledY %= OGRE_REGION_SIDE_LENGTH*2+1;
vertexScaledZ %= OGRE_REGION_SIDE_LENGTH*2+1;
//If a vertex has not yet been added, it's index is -1
index = vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material];
if((index == -1))
{
//Add the vertex
Vertex vertex(vertex1);
if(material1 == material)
vertex.colour = Vector4(1.0,1.0,1.0,1.0);
else
vertex.colour = Vector4(0.0,0.0,0.0,0.0);
vertexData[material].push_back(Vertex(vertex));
triangle.v1 = vertexData[material].size()-1;
vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material] = vertexData[material].size()-1;
}
else
{
//Just reuse the existing vertex
triangle.v1 = index;
}
//Add the triangle
indexData[material].push_back(triangle);
//Get scaled values for vertex 2
vertexScaledX = static_cast<unsigned int>((vertex2.x * 2.0) + 0.5);
vertexScaledY = static_cast<unsigned int>((vertex2.y * 2.0) + 0.5);
vertexScaledZ = static_cast<unsigned int>((vertex2.z * 2.0) + 0.5);
vertexScaledX %= OGRE_REGION_SIDE_LENGTH*2+1;
vertexScaledY %= OGRE_REGION_SIDE_LENGTH*2+1;
vertexScaledZ %= OGRE_REGION_SIDE_LENGTH*2+1;
//If a vertex has not yet been added, it's index is -1
index = vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material];
if((index == -1))
{
//Add the vertex
Vertex vertex(vertex2);
if(material2 == material)
vertex.colour = Vector4(1.0,1.0,1.0,1.0);
else
vertex.colour = Vector4(0.0,0.0,0.0,0.0);
vertexData[material].push_back(Vertex(vertex));
triangle.v2 = vertexData[material].size()-1;
vertexIndices[vertexScaledX][vertexScaledY][vertexScaledZ][material] = vertexData[material].size()-1;
}
else
{
//Just reuse the existing vertex
triangle.v2 = index;
}
//Add the triangle
indexData[material].push_back(triangle);
}
}
}

View File

@ -40,6 +40,7 @@ namespace Ogre
decl->removeAllElements();
decl->addElement(0, 0, VET_FLOAT3, VES_POSITION);
decl->addElement(0, 3 * sizeof(float), VET_FLOAT3, VES_NORMAL);
decl->addElement(0, 6 * sizeof(float), VET_FLOAT4, VES_DIFFUSE);
//LogManager::getSingleton().logMessage("Creating Vertex Buffer");
HardwareVertexBufferSharedPtr vbuf =
@ -80,6 +81,11 @@ namespace Ogre
*prPos++ = verticesToSet[i].normal.y;
*prPos++ = verticesToSet[i].normal.z;
*prPos++ = verticesToSet[i].colour.x;
*prPos++ = verticesToSet[i].colour.y;
*prPos++ = verticesToSet[i].colour.z;
*prPos++ = verticesToSet[i].colour.w;
if(verticesToSet[i].position.x < vaabMin.x)
vaabMin.x = verticesToSet[i].position.x;
if(verticesToSet[i].position.y < vaabMin.y)

View File

@ -0,0 +1,84 @@
#include "VolumeSerializer.h"
#include "Volume.h"
#include "VolumeIterator.h"
#include "OgreLogManager.h"
#include "OgreStringConverter.h"
namespace Ogre
{
VolumeSerializer::VolumeSerializer ()
{
}
VolumeSerializer::~VolumeSerializer ()
{
}
/*void VolumeSerializer::exportVolume (const Volume *pText, const Ogre::String &fileName)
{
std::ofstream outFile;
outFile.open (fileName.c_str(), std::ios::out);
outFile << pText->getString ();
outFile.close ();
}*/
void VolumeSerializer::importVolume (Ogre::DataStreamPtr &stream, Volume *pDest)
{
//pDest->setString (stream->getAsString ());
//Volume vol;
//Read volume dimensions
uchar volumeWidth = 0;
uchar volumeHeight = 0;
uchar volumeDepth = 0;
stream->read(reinterpret_cast<void*>(&volumeWidth), sizeof(volumeWidth));
stream->read(reinterpret_cast<void*>(&volumeHeight), sizeof(volumeHeight));
stream->read(reinterpret_cast<void*>(&volumeDepth), sizeof(volumeDepth));
/*if(stream->fail())
{
LogManager::getSingleton().logMessage("Failed to read dimentions");
return false;
} */
//Read data
VolumeIterator volIter(*pDest);
for(uint z = 0; z < OGRE_VOLUME_SIDE_LENGTH; ++z)
{
for(uint y = 0; y < OGRE_VOLUME_SIDE_LENGTH; ++y)
{
for(uint x = 0; x < OGRE_VOLUME_SIDE_LENGTH; ++x)
{
uchar value = 0;
stream->read(reinterpret_cast<void*>(&value), sizeof(value)); //FIXME - check for error here
/*if(value != 0)
{
LogManager::getSingleton().logMessage("Value is " + StringConverter::toString(int(value)));
}*/
volIter.setVoxelAt(x,y,z,value);
/*if(z < 24)
{
if(x % 32 < 16)
volIter.setVoxelAt(x,y,z,4);
else
volIter.setVoxelAt(x,y,z,5);
}
else
volIter.setVoxelAt(x,y,z,0);*/
}
}
//Periodically see if we can tidy the memory to avoid excessive usage during loading.
if(z%OGRE_BLOCK_SIDE_LENGTH == OGRE_BLOCK_SIDE_LENGTH-1)
{
pDest->tidy(); //FIXME - we don't actually have to tidy the whole volume here - just the part we loaded since the last call to tidy.
}
}
/*vol.load(stream->getName());*/
//pDest->setVolume(vol);
}
}