TinyRenderer: support plane shape (creating similar textured plane to OpenGL renderer)

TinyRenderer: perform clipping in double precision to improve accuracy
This commit is contained in:
Erwin Coumans
2020-08-10 20:19:00 -07:00
parent 038cc196e1
commit ff229baf1e
6 changed files with 151 additions and 29 deletions

View File

@@ -66,6 +66,8 @@ struct TinyRendererVisualShapeConverterInternalData
// Maps bodyUniqueId to a list of visual shapes belonging to the body.
btHashMap<btHashInt, btAlignedObjectArray<b3VisualShapeData> > m_visualShapesMap;
btAlignedObjectArray<unsigned char> m_checkeredTexels;
int m_uidGenerator;
int m_upAxis;
int m_swWidth;
@@ -560,10 +562,61 @@ static void convertURDFToVisualShape(const UrdfShape* visual, const char* urdfPa
} // case mesh
case URDF_GEOM_PLANE:
// TODO: plane in tiny renderer
// TODO: export visualShapeOut for external render
break;
{
glmesh = new GLInstanceGraphicsShape;
// int index = 0;
glmesh->m_indices = new b3AlignedObjectArray<int>();
glmesh->m_vertices = new b3AlignedObjectArray<GLInstanceVertex>();
glmesh->m_indices->push_back(0);
glmesh->m_indices->push_back(1);
glmesh->m_indices->push_back(2);
glmesh->m_indices->push_back(0);
glmesh->m_indices->push_back(2);
glmesh->m_indices->push_back(3);
glmesh->m_scaling[0] = 1;
glmesh->m_scaling[1] = 1;
glmesh->m_scaling[2] = 1;
glmesh->m_scaling[3] = 1;
btScalar planeConst = 0;
btVector3 planeNormal = visual->m_geometry.m_planeNormal;
btVector3 planeOrigin = planeNormal * planeConst;
btVector3 vec0, vec1;
btPlaneSpace1(planeNormal, vec0, vec1);
btScalar vecLen = 128;
btVector3 verts[4];
verts[0] = planeOrigin + vec0 * vecLen + vec1 * vecLen;
verts[1] = planeOrigin - vec0 * vecLen + vec1 * vecLen;
verts[2] = planeOrigin - vec0 * vecLen - vec1 * vecLen;
verts[3] = planeOrigin + vec0 * vecLen - vec1 * vecLen;
GLInstanceVertex vtx;
vtx.xyzw[0] = verts[0][0]; vtx.xyzw[1] = verts[0][1]; vtx.xyzw[2] = 0; vtx.xyzw[3] = 0;
vtx.normal[0] = 0; vtx.normal[1] = 0; vtx.normal[2] = 1;
vtx.uv[0] = vecLen; vtx.uv[1] = vecLen;
glmesh->m_vertices->push_back(vtx);
vtx.xyzw[0] = verts[1][0]; vtx.xyzw[1] = verts[1][1]; vtx.xyzw[2] = 0; vtx.xyzw[3] = 0;
vtx.normal[0] = 0; vtx.normal[1] = 0; vtx.normal[2] = 1;
vtx.uv[0] = 0; vtx.uv[1] = vecLen;
glmesh->m_vertices->push_back(vtx);
vtx.xyzw[0] = verts[2][0]; vtx.xyzw[1] = verts[2][1]; vtx.xyzw[2] = 0; vtx.xyzw[3] = 0;
vtx.normal[0] = 0; vtx.normal[1] = 0; vtx.normal[2] = 1;
vtx.uv[0] = 0; vtx.uv[1] = 0;
glmesh->m_vertices->push_back(vtx);
vtx.xyzw[0] = verts[3][0]; vtx.xyzw[1] = verts[3][1]; vtx.xyzw[2] = 0; vtx.xyzw[3] = 0;
vtx.normal[0] = 0; vtx.normal[1] = 0; vtx.normal[2] = 1;
vtx.uv[0] = vecLen; vtx.uv[1] = 0;
glmesh->m_vertices->push_back(vtx);
glmesh->m_numIndices = glmesh->m_indices->size();
glmesh->m_numvertices = glmesh->m_vertices->size();
break;
}
default:
{
b3Warning("TinyRenderer: unknown visual geometry type %i\n", visual->m_geometry.m_type);
@@ -783,6 +836,45 @@ int TinyRendererVisualShapeConverter::convertVisualShapes(
{
B3_PROFILE("convertURDFToVisualShape");
convertURDFToVisualShape(vis, pathPrefix, localInertiaFrame.inverse() * childTrans, vertices, indices, textures, visualShape, fileIO, m_data->m_flags);
if ((vis->m_geometry.m_type == URDF_GEOM_PLANE) || (vis->m_geometry.m_type == URDF_GEOM_SPHERE))
{
int texWidth = 1024;
int texHeight = 1024;
if (m_data->m_checkeredTexels.size() == 0)
{
int red = 173;
int green = 199;
int blue = 255;
//create a textured surface
m_data->m_checkeredTexels.resize(texWidth * texHeight * 3);
for (int i = 0; i < texWidth * texHeight * 3; i++)
m_data->m_checkeredTexels[i] = 255;
for (int i = 0; i < texWidth; i++)
{
for (int j = 0; j < texHeight; j++)
{
int a = i < texWidth / 2 ? 1 : 0;
int b = j < texWidth / 2 ? 1 : 0;
if (a == b)
{
m_data->m_checkeredTexels[(i + j * texWidth) * 3 + 0] = red;
m_data->m_checkeredTexels[(i + j * texWidth) * 3 + 1] = green;
m_data->m_checkeredTexels[(i + j * texWidth) * 3 + 2] = blue;
}
}
}
}
MyTexture2 texData;
texData.m_width = texWidth;
texData.m_height = texHeight;
texData.textureData1 = &m_data->m_checkeredTexels[0];
texData.m_isCached = true;
textures.push_back(texData);
}
}
rgbaColor[0] = visualShape.m_rgbaColor[0];

View File

@@ -167,11 +167,11 @@ struct Shader : public IShader
Vec2f uv = varying_uv * bar;
Vec3f reflection_direction = (bn * (bn * m_light_dir_local * 2.f) - m_light_dir_local).normalize();
float specular = std::pow(b3Max(reflection_direction.z, 0.f),
m_model->specular(uv));
float diffuse = b3Max(0.f, bn * m_light_dir_local);
float specular = std::pow(b3Max(reflection_direction.z, 0.f),
m_model->specular(uv));
float diffuse = b3Max(0.f, bn * m_light_dir_local);
color = m_model->diffuse(uv);
color = m_model->diffuse(uv);
color[0] *= m_colorRGBA[0];
color[1] *= m_colorRGBA[1];
color[2] *= m_colorRGBA[2];

View File

@@ -315,8 +315,10 @@ template <size_t DimRows,size_t DimCols,class T> std::ostream& operator<<(std::o
/////////////////////////////////////////////////////////////////////////////////
typedef vec<2, float> Vec2f;
typedef vec<2, double> Vec2d;
typedef vec<2, int> Vec2i;
typedef vec<3, float> Vec3f;
typedef vec<3, double> Vec3d;
typedef vec<3, int> Vec3i;
typedef vec<4, float> Vec4f;
typedef mat<4, 4, float> Matrix;

View File

@@ -166,10 +166,10 @@ TGAColor Model::diffuse(Vec2f uvf)
// bool repeat = true;
// if (repeat)
{
uvf[0] = std::modf(uvf[0], &val);
uvf[1] = std::modf(uvf[1], &val);
}
Vec2i uv(uvf[0] * diffusemap_.get_width(), uvf[1] * diffusemap_.get_height());
uvf[0] = std::modf(uvf[0], &val);
uvf[1] = std::modf(uvf[1], &val);
}
Vec2i uv(uvf[0] * diffusemap_.get_width(), uvf[1] * diffusemap_.get_height());
return diffusemap_.get(uv[0], uv[1]);
}
return TGAColor(255, 255, 255, 255);

View File

@@ -61,19 +61,25 @@ Matrix lookat(Vec3f eye, Vec3f center, Vec3f up)
return ModelView;
}
Vec3f barycentric(Vec2f A, Vec2f B, Vec2f C, Vec2f P)
Vec3d barycentric(Vec2f A1, Vec2f B1, Vec2f C1, Vec2f P1)
{
Vec3f s[2];
Vec2d A(A1.x, A1.y);
Vec2d B(B1.x, B1.y);
Vec2d C(C1.x, C1.y);
Vec2d P(P1.x, P1.y);;
Vec3d s[2];
for (int i = 2; i--;)
{
s[i][0] = C[i] - A[i];
s[i][1] = B[i] - A[i];
s[i][2] = A[i] - P[i];
}
Vec3f u = cross(s[0], s[1]);
Vec3d u = cross(s[0], s[1]);
if (std::abs(u[2]) > 1e-2) // dont forget that u[2] is integer. If it is zero then triangle ABC is degenerate
return Vec3f(1.f - (u.x + u.y) / u.z, u.y / u.z, u.x / u.z);
return Vec3f(-1, 1, 1); // in this case generate negative coordinates, it will be thrown away by the rasterizator
return Vec3d(1. - (u.x + u.y) / u.z, u.y / u.z, u.x / u.z);
return Vec3d(-1., 1., 1.); // in this case generate negative coordinates, it will be thrown away by the rasterizator
}
void triangleClipped(mat<4, 3, float> &clipc, mat<4, 3, float> &orgClipc, IShader &shader, TGAImage &image, float *zbuffer, const Matrix &viewPortMatrix)
@@ -119,25 +125,28 @@ void triangleClipped(mat<4, 3, float> &clipc, mat<4, 3, float> &orgClipc, IShade
{
for (P.y = bboxmin.y; P.y <= bboxmax.y; P.y++)
{
float frag_depth = 0;
double frag_depth = 0;
{
Vec3f bc_screen = barycentric(pts2[0], pts2[1], pts2[2], P);
Vec3f bc_clip = Vec3f(bc_screen.x / screenSpacePts[0][3], bc_screen.y / screenSpacePts[1][3], bc_screen.z / screenSpacePts[2][3]);
Vec3d bc_screen = barycentric(pts2[0], pts2[1], pts2[2], P);
Vec3d bc_clip = Vec3d(bc_screen.x / screenSpacePts[0][3], bc_screen.y / screenSpacePts[1][3], bc_screen.z / screenSpacePts[2][3]);
bc_clip = bc_clip / (bc_clip.x + bc_clip.y + bc_clip.z);
frag_depth = -1 * (clipc[2] * bc_clip);
Vec3d clipd(clipc[2].x, clipc[2].y, clipc[2].z);
frag_depth = -1. * (clipd * bc_clip);
if (bc_screen.x < 0 || bc_screen.y < 0 || bc_screen.z < 0 ||
zbuffer[P.x + P.y * image.get_width()] > frag_depth)
continue;
}
Vec3f bc_screen2 = barycentric(orgPts2[0], orgPts2[1], orgPts2[2], P);
Vec3f bc_clip2 = Vec3f(bc_screen2.x / orgScreenSpacePts[0][3], bc_screen2.y / orgScreenSpacePts[1][3], bc_screen2.z / orgScreenSpacePts[2][3]);
Vec3d bc_screen2 = barycentric(orgPts2[0], orgPts2[1], orgPts2[2], P);
Vec3d bc_clip2 = Vec3d(bc_screen2.x / orgScreenSpacePts[0][3], bc_screen2.y / orgScreenSpacePts[1][3], bc_screen2.z / orgScreenSpacePts[2][3]);
bc_clip2 = bc_clip2 / (bc_clip2.x + bc_clip2.y + bc_clip2.z);
float frag_depth2 = -1 * (orgClipc[2] * bc_clip2);
bool discard = shader.fragment(bc_clip2, color);
Vec3d orgClipd(orgClipc[2].x, orgClipc[2].y, orgClipc[2].z);
double frag_depth2 = -1. * (orgClipd * bc_clip2);
Vec3f bc_clip2f(bc_clip2.x, bc_clip2.y, bc_clip2.z);
bool discard = shader.fragment(bc_clip2f, color);
if (!discard)
{
zbuffer[P.x + P.y * image.get_width()] = frag_depth;
@@ -182,14 +191,16 @@ void triangle(mat<4, 3, float> &clipc, IShader &shader, TGAImage &image, float *
{
for (P.y = bboxmin.y; P.y <= bboxmax.y; P.y++)
{
Vec3f bc_screen = barycentric(pts2[0], pts2[1], pts2[2], P);
Vec3f bc_clip = Vec3f(bc_screen.x / pts[0][3], bc_screen.y / pts[1][3], bc_screen.z / pts[2][3]);
Vec3d bc_screen = barycentric(pts2[0], pts2[1], pts2[2], P);
Vec3d bc_clip = Vec3d(bc_screen.x / pts[0][3], bc_screen.y / pts[1][3], bc_screen.z / pts[2][3]);
bc_clip = bc_clip / (bc_clip.x + bc_clip.y + bc_clip.z);
float frag_depth = -1 * (clipc[2] * bc_clip);
Vec3d clipd(clipc[2].x, clipc[2].y, clipc[2].z);
double frag_depth = -1. * (clipd * bc_clip);
if (bc_screen.x < 0 || bc_screen.y < 0 || bc_screen.z < 0 ||
zbuffer[P.x + P.y * image.get_width()] > frag_depth)
continue;
bool discard = shader.fragment(bc_clip, color);
Vec3f bc_clipf(bc_clip.x, bc_clip.y, bc_clip.z);
bool discard = shader.fragment(bc_clipf, color);
if (frag_depth < -shader.m_farPlane)
discard = true;
if (frag_depth > shader.m_nearPlane)

View File

@@ -296,6 +296,23 @@ bool TGAImage::unload_rle_data(std::ofstream &out) const
TGAColor TGAImage::get(int x, int y) const
{
if (x < 0)
{
x = 0;
}
if (y < 0)
{
y = 0;
}
if (x >= width)
{
x = width - 1;
}
if (y >= height)
{
y = height - 1;
}
if (!data || x < 0 || y < 0 || x >= width || y >= height)
{
return TGAColor(128.f, 128.f, 128.f, 255.f);