Mesh rendering bug fixes and improvements:

- Defined a sensible lighting model to use when normals are omitted from a model, which should prevent crashes in the Mac version
- Added support for point sprites in cmod meshes
ver1_5_1
Chris Laurel 2007-04-02 16:55:32 +00:00
parent e938b9012a
commit 6454b452d4
10 changed files with 227 additions and 69 deletions

View File

@ -187,6 +187,7 @@ Mesh::PrimitiveGroup::getPrimitiveCount() const
case LineStrip:
return nIndices - 2;
case PointList:
case SpriteList:
return nIndices;
default:
// Invalid value
@ -621,6 +622,8 @@ Mesh::parsePrimitiveGroupType(const string& name)
return LineStrip;
else if (name == "points")
return PointList;
else if (name == "sprites")
return SpriteList;
else
return InvalidPrimitiveGroupType;
}
@ -647,6 +650,8 @@ Mesh::parseVertexAttributeSemantic(const string& name)
return Texture2;
else if (name == "texcoord3")
return Texture3;
else if (name == "pointsize")
return PointSize;
else
return InvalidSemantic;
}

View File

@ -35,7 +35,8 @@ class Mesh
Texture1 = 6,
Texture2 = 7,
Texture3 = 8,
SemanticMax = 9,
PointSize = 9,
SemanticMax = 10,
InvalidSemantic = -1,
};
@ -133,7 +134,8 @@ class Mesh
LineList = 3,
LineStrip = 4,
PointList = 5,
PrimitiveTypeMax = 6,
SpriteList = 6,
PrimitiveTypeMax = 7,
InvalidPrimitiveGroupType = -1
};
@ -213,32 +215,5 @@ class Mesh
std::string name;
};
#if 0
#include <celmath/frustum.h>
#include <celmath/ray.h>
class Mesh
{
public:
virtual ~Mesh() {};
virtual void render(float lod) = 0;
virtual void render(unsigned int attributes, float lod) = 0;
virtual void render(unsigned int attributes, const Frustum&, float lod) = 0;
virtual bool pick(const Ray3d&, double&) { return false; };
enum {
Normals = 0x01,
Tangents = 0x02,
Colors = 0x04,
TexCoords0 = 0x08,
TexCoords1 = 0x10,
VertexProgParams = 0x1000,
Multipass = 0x10000000,
};
};
#endif
#endif // !_CELMESH_MESH_H_

View File

@ -74,7 +74,8 @@ defined here--they have the obvious definitions.
<vertex_attribute> ::= <vertex_semantic> <vertex_format>
<vertex_semantic> ::= position | normal | color0 | color1 | tangent |
texcoord0 | texcoord1 | texcoord2 | texcoord3
texcoord0 | texcoord1 | texcoord2 | texcoord3 |
pointsize
<vertex_format> ::= f1 | f2 | f3 | f4 | ub4
@ -87,7 +88,8 @@ defined here--they have the obvious definitions.
{ <unsigned_int> }
<prim_group_type> ::= trilist | tristrip | trifan |
linelist | linestrip | points
linelist | linestrip | points |
sprites
<material_index> :: <unsigned_int> | -1
\endcode
@ -797,6 +799,8 @@ AsciiModelWriter::writeGroup(const Mesh::PrimitiveGroup& group)
out << "linestrip"; break;
case Mesh::PointList:
out << "points"; break;
case Mesh::SpriteList:
out << "sprites"; break;
default:
return;
}
@ -928,6 +932,9 @@ AsciiModelWriter::writeVertexDescription(const Mesh::VertexDescription& desc)
case Mesh::Texture3:
out << "texcoord3";
break;
case Mesh::PointSize:
out << "pointsize";
break;
default:
assert(0);
break;

View File

@ -26,7 +26,8 @@ static GLenum GLPrimitiveModes[Mesh::PrimitiveTypeMax] =
GL_TRIANGLE_FAN,
GL_LINES,
GL_LINE_STRIP,
GL_POINTS
GL_POINTS,
GL_POINTS,
};
static GLenum GLComponentTypes[Mesh::FormatMax] =
@ -50,6 +51,7 @@ static int GLComponentCounts[Mesh::FormatMax] =
enum {
TangentAttributeIndex = 6,
PointSizeAttributeIndex = 7,
};
@ -64,7 +66,10 @@ setExtendedVertexArrays(const Mesh::VertexDescription& desc,
RenderContext::RenderContext() :
material(&defaultMaterial),
locked(false),
renderPass(PrimaryPass)
usePointSize(false),
useNormals(true),
renderPass(PrimaryPass),
pointScale(1.0f)
{
}
@ -85,6 +90,13 @@ static void setVertexArrays(const Mesh::VertexDescription& desc)
#endif
const Mesh::Material*
RenderContext::getMaterial() const
{
return material;
}
void
RenderContext::setMaterial(const Mesh::Material* newMaterial)
{
@ -114,6 +126,20 @@ RenderContext::setMaterial(const Mesh::Material* newMaterial)
}
void
RenderContext::setPointScale(float _pointScale)
{
pointScale = _pointScale;
}
float
RenderContext::getPointScale() const
{
return pointScale;
}
void
RenderContext::drawGroup(const Mesh::PrimitiveGroup& group)
{
@ -125,10 +151,21 @@ RenderContext::drawGroup(const Mesh::PrimitiveGroup& group)
return;
}
if (group.prim == Mesh::SpriteList)
{
glEnable(GL_POINT_SPRITE_ARB);
glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
}
glDrawElements(GLPrimitiveModes[(int) group.prim],
group.nIndices,
GL_UNSIGNED_INT,
group.indices);
if (group.prim == Mesh::SpriteList)
{
glDisable(GL_POINT_SPRITE_ARB);
}
}
@ -176,11 +213,6 @@ FixedFunctionRenderContext::makeCurrent(const Mesh::Material& m)
t->bind();
}
glColor4f(m.diffuse.red(),
m.diffuse.green(),
m.diffuse.blue(),
m.opacity);
bool blendOnNow = false;
if (m.opacity != 1.0f || (t != NULL && t->hasAlpha()))
blendOnNow = true;
@ -204,31 +236,56 @@ FixedFunctionRenderContext::makeCurrent(const Mesh::Material& m)
}
}
if (m.specular == Color::Black)
if (useNormals)
{
float matSpecular[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
float zero = 0.0f;
glMaterialfv(GL_FRONT, GL_SPECULAR, matSpecular);
glMaterialfv(GL_FRONT, GL_SHININESS, &zero);
specularOn = false;
glColor4f(m.diffuse.red(),
m.diffuse.green(),
m.diffuse.blue(),
m.opacity);
if (m.specular == Color::Black)
{
float matSpecular[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
float zero = 0.0f;
glMaterialfv(GL_FRONT, GL_SPECULAR, matSpecular);
glMaterialfv(GL_FRONT, GL_SHININESS, &zero);
specularOn = false;
}
else
{
float matSpecular[4] = { m.specular.red(),
m.specular.green(),
m.specular.blue(),
0.0f };
glMaterialfv(GL_FRONT, GL_SPECULAR, matSpecular);
glMaterialfv(GL_FRONT, GL_SHININESS, &m.specularPower);
specularOn = true;
}
{
float matEmissive[4] = { m.emissive.red(),
m.emissive.green(),
m.emissive.blue(),
0.0f };
glMaterialfv(GL_FRONT, GL_EMISSION, matEmissive);
}
}
else
{
float matSpecular[4] = { m.specular.red(),
m.specular.green(),
m.specular.blue(),
0.0f };
glMaterialfv(GL_FRONT, GL_SPECULAR, matSpecular);
glMaterialfv(GL_FRONT, GL_SHININESS, &m.specularPower);
specularOn = true;
}
{
float matEmissive[4] = { m.emissive.red(),
m.emissive.green(),
m.emissive.blue(),
0.0f };
glMaterialfv(GL_FRONT, GL_EMISSION, matEmissive);
// When lighting without normals, we'll just merge everything
// into the emissive color. This makes normal-less lighting work
// more like it does in the GLSL path, though it's not very
// useful without shadows.
float matBlack[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
glMaterialfv(GL_FRONT, GL_DIFFUSE, matBlack);
glMaterialfv(GL_FRONT, GL_SPECULAR, matBlack);
{
float matEmissive[4] = { m.emissive.red() + m.diffuse.red(),
m.emissive.green() + m.diffuse.green(),
m.emissive.blue() + m.diffuse.blue(),
m.opacity };
glMaterialfv(GL_FRONT, GL_EMISSION, matEmissive);
}
}
}
else if (getRenderPass() == EmissivePass)
@ -253,6 +310,17 @@ FixedFunctionRenderContext::makeCurrent(const Mesh::Material& m)
void
FixedFunctionRenderContext::setVertexArrays(const Mesh::VertexDescription& desc, void* vertexData)
{
// Update the material if normals appear or disappear in the vertex
// description.
bool useNormalsNow = (desc.getAttribute(Mesh::Normal).format == Mesh::Float3);
if (useNormalsNow != useNormals)
{
useNormals = useNormalsNow;
if (getMaterial() != NULL)
makeCurrent(*getMaterial());
}
setStandardVertexArrays(desc, vertexData);
}
@ -366,6 +434,23 @@ setExtendedVertexArrays(const Mesh::VertexDescription& desc,
glx::glDisableVertexAttribArrayARB(TangentAttributeIndex);
break;
}
const Mesh::VertexAttribute& pointsize = desc.getAttribute(Mesh::PointSize);
switch (pointsize.format)
{
case Mesh::Float1:
glx::glEnableVertexAttribArrayARB(PointSizeAttributeIndex);
glx::glVertexAttribPointerARB(PointSizeAttributeIndex,
GLComponentCounts[(int) pointsize.format],
GLComponentTypes[(int) pointsize.format],
GL_FALSE,
desc.stride,
vertices + pointsize.offset);
break;
default:
glx::glDisableVertexAttribArrayARB(PointSizeAttributeIndex);
break;
}
}
@ -388,6 +473,7 @@ GLSL_RenderContext::~GLSL_RenderContext()
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glx::glDisableVertexAttribArrayARB(TangentAttributeIndex);
glx::glDisableVertexAttribArrayARB(PointSizeAttributeIndex);
}
@ -429,10 +515,19 @@ GLSL_RenderContext::makeCurrent(const Mesh::Material& m)
shaderProps.texUsage = ShaderProperties::SharedTextureCoords;
if (lunarLambert == 0.0f)
shaderProps.lightModel = ShaderProperties::DiffuseModel;
if (useNormals)
{
if (lunarLambert == 0.0f)
shaderProps.lightModel = ShaderProperties::DiffuseModel;
else
shaderProps.lightModel = ShaderProperties::LunarLambertModel;
}
else
shaderProps.lightModel = ShaderProperties::LunarLambertModel;
{
// "particle diffuse" lighting is the only type that doesn't
// depend on having a surface normal.
shaderProps.lightModel = ShaderProperties::ParticleDiffuseModel;
}
if (m.maps[Mesh::DiffuseMap] != InvalidResource)
{
@ -458,7 +553,7 @@ GLSL_RenderContext::makeCurrent(const Mesh::Material& m)
}
}
if (m.specular != Color::Black)
if (m.specular != Color::Black && useNormals)
{
shaderProps.lightModel = ShaderProperties::PerPixelSpecularModel;
specTex = GetTextureManager()->find(m.maps[Mesh::SpecularMap]);
@ -484,6 +579,9 @@ GLSL_RenderContext::makeCurrent(const Mesh::Material& m)
}
}
if (usePointSize)
shaderProps.texUsage |= ShaderProperties::PointSprite;
if (atmosphere != NULL)
{
// Only use new atmosphere code in OpenGL 2.0 path when new style parameters are defined.
@ -530,6 +628,11 @@ GLSL_RenderContext::makeCurrent(const Mesh::Material& m)
prog->setAtmosphereParameters(*atmosphere, objRadius, objRadius);
}
if ((shaderProps.texUsage & ShaderProperties::PointSprite) != 0)
{
prog->pointScale = getPointScale();
}
bool blendOnNow = false;
if (m.opacity != 1.0f || (baseTex != NULL && baseTex->hasAlpha()))
blendOnNow = true;
@ -554,10 +657,26 @@ GLSL_RenderContext::makeCurrent(const Mesh::Material& m)
void
GLSL_RenderContext::setVertexArrays(const Mesh::VertexDescription& desc,
void* vertexData)
void* vertexData)
{
setStandardVertexArrays(desc, vertexData);
setExtendedVertexArrays(desc, vertexData);
// Normally, the shader that will be used depends only on the material.
// But the presence of point size and normals can also affect the
// shader, so force an update of the material if those attributes appear
// or disappear in the new set of vertex arrays.
bool usePointSizeNow = (desc.getAttribute(Mesh::PointSize).format == Mesh::Float1);
bool useNormalsNow = (desc.getAttribute(Mesh::Normal).format == Mesh::Float3);
if (usePointSizeNow != usePointSize ||
useNormalsNow != useNormals)
{
usePointSize = usePointSizeNow;
useNormals = useNormalsNow;
if (getMaterial() != NULL)
makeCurrent(*getMaterial());
}
}

View File

@ -26,6 +26,7 @@ class RenderContext
void* vertexData) = 0;
virtual void drawGroup(const Mesh::PrimitiveGroup& group);
const Mesh::Material* getMaterial() const;
void setMaterial(const Mesh::Material*);
void lock() { locked = true; }
void unlock() { locked = false; }
@ -39,11 +40,19 @@ class RenderContext
RenderPass getRenderPass() const { return renderPass; }
void setRenderPass(RenderPass rp) { renderPass = rp; }
void setPointScale(float);
float getPointScale() const;
private:
const Mesh::Material* material;
bool locked;
RenderPass renderPass;
float pointScale;
protected:
bool usePointSize;
bool useNormals;
};

View File

@ -4977,6 +4977,7 @@ void Renderer::renderObject(Point3f pos,
ri.orientation = cameraOrientation;
ri.pixWidth = discSizeInPixels;
ri.pointScale = obj.radius / pixelSize;
// Set up the colors
if (ri.baseTex == NULL ||

View File

@ -251,11 +251,13 @@ void renderModel_GLSL(Model* model,
rc.setAtmosphere(atmosphere);
}
rc.setPointScale(ri.pointScale);
// Handle extended material attributes (per model only, not per submesh)
rc.setLunarLambert(ri.lunarLambert);
// Handle material override; a texture specified in an ssc file will override
// all materials specified in the model file.
// Handle material override; a texture specified in an ssc file will
// override all materials specified in the model file.
if (texOverride != InvalidResource)
{
Mesh::Material m;

View File

@ -27,6 +27,7 @@ struct RenderInfo
float lunarLambert;
Quatf orientation;
float pixWidth;
float pointScale;
bool useTexEnvCombine;
RenderInfo() : color(1.0f, 1.0f, 1.0f),

View File

@ -136,6 +136,7 @@ ShaderProperties::isViewDependent() const
switch (lightModel)
{
case DiffuseModel:
case ParticleDiffuseModel:
return false;
default:
return true;
@ -454,8 +455,18 @@ AddDirectionalLightContrib(unsigned int i, const ShaderProperties& props)
{
string source;
source += "NL = max(0.0, dot(gl_Normal, " +
LightProperty(i, "direction") + "));\n";
if (props.lightModel == ShaderProperties::ParticleDiffuseModel)
{
// The ParticleDiffuse model doesn't use a surface normal; vertices
// are lit as if they were infinitesimal spherical particles,
// unaffected by light direction except when considering shadows.
source += "NL = 1.0;\n";
}
else
{
source += "NL = max(0.0, dot(gl_Normal, " +
LightProperty(i, "direction") + "));\n";
}
if (props.lightModel == ShaderProperties::SpecularModel)
{
@ -890,6 +901,12 @@ ShaderManager::buildVertexShader(const ShaderProperties& props)
source += "float NV = dot(gl_Normal, eyeDir);\n";
}
if (props.texUsage & ShaderProperties::PointSprite)
{
source += "uniform float pointScale;\n";
source += "attribute float pointSize;\n";
}
if (props.usesTangentSpaceLighting())
{
source += "attribute vec3 tangent;\n";
@ -1135,6 +1152,11 @@ ShaderManager::buildVertexShader(const ShaderProperties& props)
source += "position_obj = gl_Vertex.xyz;\n";
}
if ((props.texUsage & ShaderProperties::PointSprite) != 0)
{
source += "gl_PointSize = pointScale * pointSize / length(vec3(gl_ModelViewMatrix * gl_Vertex));\n";
}
source += "gl_Position = ftransform();\n";
source += "}\n";
@ -1793,6 +1815,13 @@ ShaderManager::buildProgram(const ShaderProperties& props)
// someplace)
glx::glBindAttribLocationARB(prog->getID(), 6, "tangent");
}
if (props.texUsage & ShaderProperties::PointSprite)
{
// Point size is always in attribute 7
glx::glBindAttribLocationARB(prog->getID(), 7, "pointSize");
}
status = prog->link();
}
}
@ -1942,6 +1971,11 @@ CelestiaGLProgram::initParameters()
{
lunarLambert = floatParam("lunarLambert");
}
if ((props.texUsage & ShaderProperties::PointSprite) != 0)
{
pointScale = floatParam("pointScale");
}
}

View File

@ -43,6 +43,7 @@ class ShaderProperties
CloudShadowTexture = 0x80,
CompressedNormalTexture = 0x100,
Scattering = 0x2000,
PointSprite = 0x4000,
SharedTextureCoords = 0x8000,
};
@ -55,6 +56,7 @@ class ShaderProperties
OrenNayarModel = 4,
AtmosphereModel = 5,
LunarLambertModel = 6,
ParticleDiffuseModel = 7,
};
enum
@ -170,7 +172,10 @@ class CelestiaGLProgram
// x = radius
// y = radius^2
// z = 1/radius
Vec3ShaderParameter atmosphereRadius;
Vec3ShaderParameter atmosphereRadius;
// Scale factor for point sprites
FloatShaderParameter pointScale;
CelestiaGLProgramShadow shadows[MaxShaderLights][MaxShaderShadows];