Merge pull request #1063 from erwincoumans/master

TinyRenderer: implement triangle clipping against near-plane, uv repeat
This commit is contained in:
erwincoumans
2017-04-07 04:44:28 +00:00
committed by GitHub
6 changed files with 270 additions and 61 deletions

View File

@@ -746,16 +746,13 @@ upAxisMat.setIdentity();
btTriangleMesh* meshInterface = new btTriangleMesh();
for (int i=0; i<glmesh->m_numIndices/3; i++)
{
float* v0 = glmesh->m_vertices->at(glmesh->m_indices->at(i*3)).xyzw;
float* v1 = glmesh->m_vertices->at(glmesh->m_indices->at(i*3+1)).xyzw;
float* v2 = glmesh->m_vertices->at(glmesh->m_indices->at(i*3+2)).xyzw;
meshInterface->addTriangle(
btVector3(v0[0],v0[1],v0[2]),
btVector3(v1[0],v1[1],v1[2]),
btVector3(v2[0],v2[1],v2[2]));
const btVector3& v0 = convertedVerts[glmesh->m_indices->at(i*3)];
const btVector3& v1 = convertedVerts[glmesh->m_indices->at(i*3+1)];
const btVector3& v2 = convertedVerts[glmesh->m_indices->at(i*3+2)];
meshInterface->addTriangle(v0,v1,v2);
}
btBvhTriangleMeshShape* trimesh = new btBvhTriangleMeshShape(meshInterface,true,true);
trimesh->setLocalScaling(collision->m_geometry.m_meshScale);
//trimesh->setLocalScaling(collision->m_geometry.m_meshScale);
shape = trimesh;
} else
@@ -765,7 +762,7 @@ upAxisMat.setIdentity();
convexHull->optimizeConvexHull();
//convexHull->initializePolyhedralFeatures();
convexHull->setMargin(gUrdfDefaultCollisionMargin);
convexHull->setLocalScaling(collision->m_geometry.m_meshScale);
//convexHull->setLocalScaling(collision->m_geometry.m_meshScale);
shape = convexHull;
}

View File

@@ -89,10 +89,10 @@ protected:
virtual void resetCamera()
{
float dist = 4;
float pitch = 193;
float yaw = 25;
float targetPos[3]={0,0,0.5};//-3,2.8,-2.5};
float dist = 3.45;
float pitch = 287;
float yaw = 16.2;
float targetPos[3]={2.05,0.02,0.53};//-3,2.8,-2.5};
m_guiHelper->resetCamera(dist,pitch,yaw,targetPos[0],targetPos[1],targetPos[2]);
}
@@ -256,7 +256,11 @@ void PhysicsClientExample::prepareAndSubmitCommand(int commandId)
case CMD_LOAD_SDF:
{
b3SharedMemoryCommandHandle commandHandle = b3LoadSdfCommandInit(m_physicsClientHandle, "two_cubes.sdf");//kuka_iiwa/model.sdf");
#ifdef BT_DEBUG
b3SharedMemoryCommandHandle commandHandle = b3LoadSdfCommandInit(m_physicsClientHandle, "two_cubes.sdf");
#else
b3SharedMemoryCommandHandle commandHandle = b3LoadSdfCommandInit(m_physicsClientHandle, "kitchens/1.sdf");//two_cubes.sdf");//kitchens/1.sdf");//kuka_iiwa/model.sdf");
#endif
b3SubmitClientCommand(m_physicsClientHandle, commandHandle);
break;
}
@@ -834,13 +838,16 @@ void PhysicsClientExample::stepSimulation(float deltaTime)
//todo: rescale the depthValue to [0..255]
if (depthValue>-1e20)
{
int rgb = (depthValue-minDepthValue)*(255. / (btFabs(maxDepthValue-minDepthValue)));
int rgb = 0;
if (maxDepthValue!=minDepthValue)
{
rgb = (depthValue-minDepthValue)*(255. / (btFabs(maxDepthValue-minDepthValue)));
if (rgb<0 || rgb>255)
{
printf("rgb=%d\n",rgb);
//printf("rgb=%d\n",rgb);
}
}
m_canvas->setPixel(m_canvasDepthIndex,i,j,
rgb,
rgb,

View File

@@ -377,42 +377,91 @@ TinyRenderObjectData::~TinyRenderObjectData()
delete m_model;
}
void TinyRenderer::renderObjectDepth(TinyRenderObjectData& renderData)
static bool equals(const Vec4f& vA, const Vec4f& vB)
{
int width = renderData.m_rgbColorBuffer.get_width();
int height = renderData.m_rgbColorBuffer.get_height();
return false;
}
Vec3f light_dir_local = Vec3f(renderData.m_lightDirWorld[0],renderData.m_lightDirWorld[1],renderData.m_lightDirWorld[2]);
float light_distance = renderData.m_lightDistance;
Model* model = renderData.m_model;
if (0==model)
static void clipEdge(const mat<4,3,float>& triangleIn, int vertexIndexA, int vertexIndexB, b3AlignedObjectArray<Vec4f>& vertices)
{
Vec4f v0New = triangleIn.col(vertexIndexA);
Vec4f v1New = triangleIn.col(vertexIndexB);
bool v0Inside = v0New[3] > 0.f && v0New[2] > -v0New[3];
bool v1Inside= v1New[3] > 0.f && v1New[2] > -v1New[3];
if (v0Inside && v1Inside)
{
} else if (v0Inside || v1Inside)
{
float d0 = v0New[2]+v0New[3];
float d1 = v1New[2]+v1New[3];
float factor = 1.0 / (d1-d0);
Vec4f newVertex =(v0New*d1-v1New*d0)*factor;
if (v0Inside)
{
v1New = newVertex;
} else
{
v0New = newVertex;
}
} else
{
return;
}
renderData.m_viewportMatrix = viewport(0,0,width, height);
float* shadowBufferPtr = (renderData.m_shadowBuffer && renderData.m_shadowBuffer->size())?&renderData.m_shadowBuffer->at(0):0;
int* segmentationMaskBufferPtr = 0;
TGAImage depthFrame(width, height, TGAImage::RGB);
if (vertices.size()==0 || !(equals(vertices[vertices.size()-1],v0New)))
{
// light target is set to be the origin, and the up direction is set to be vertical up.
Matrix lightViewMatrix = lookat(light_dir_local*light_distance, Vec3f(0.0,0.0,0.0), Vec3f(0.0,0.0,1.0));
Matrix lightModelViewMatrix = lightViewMatrix*renderData.m_modelMatrix;
Matrix lightViewProjectionMatrix = renderData.m_projectionMatrix;
Vec3f localScaling(renderData.m_localScaling[0],renderData.m_localScaling[1],renderData.m_localScaling[2]);
vertices.push_back(v0New);
}
DepthShader shader(model, lightModelViewMatrix, lightViewProjectionMatrix,renderData.m_modelMatrix, localScaling, light_distance);
vertices.push_back(v1New);
}
for (int i=0; i<model->nfaces(); i++)
static bool clipTriangleAgainstNearplane(const mat<4,3,float>& triangleIn, b3AlignedObjectArray<mat<4,3,float> >& clippedTrianglesOut)
{
for (int j=0; j<3; j++) {
shader.vertex(i, j);
}
triangle(shader.varying_tri, shader, depthFrame, shadowBufferPtr, segmentationMaskBufferPtr, renderData.m_viewportMatrix, renderData.m_objectIndex);
}
//discard triangle if all vertices are behind near-plane
if (triangleIn[3][0]<0 && triangleIn[3][1] <0 && triangleIn[3][2] <0)
{
return true;
}
//accept triangle if all vertices are in front of the near-plane
if (triangleIn[3][0]>=0 && triangleIn[3][1] >=0 && triangleIn[3][2] >=0)
{
clippedTrianglesOut.push_back(triangleIn);
return false;
}
Vec4f vtxCache[5];
b3AlignedObjectArray<Vec4f> vertices;
vertices.initializeFromBuffer(vtxCache,0,5);
clipEdge(triangleIn,0,1,vertices);
clipEdge(triangleIn,1,2,vertices);
clipEdge(triangleIn,2,0,vertices);
if (vertices.size()<3)
return true;
if (equals(vertices[0],vertices[vertices.size()-1]))
{
vertices.pop_back();
}
//create a fan of triangles
for (int i=1;i<vertices.size()-1;i++)
{
mat<4,3,float>& vtx = clippedTrianglesOut.expand();
vtx.set_col(0,vertices[0]);
vtx.set_col(1,vertices[i]);
vtx.set_col(2,vertices[i+1]);
}
return true;
}
void TinyRenderer::renderObject(TinyRenderObjectData& renderData)
@@ -449,8 +498,83 @@ void TinyRenderer::renderObject(TinyRenderObjectData& renderData)
for (int j=0; j<3; j++) {
shader.vertex(i, j);
}
mat<4,3,float> stackTris[3];
b3AlignedObjectArray< mat<4,3,float> > clippedTriangles;
clippedTriangles.initializeFromBuffer(stackTris,0,3);
bool hasClipped = clipTriangleAgainstNearplane(shader.varying_tri,clippedTriangles);
if (hasClipped)
{
for (int t=0;t<clippedTriangles.size();t++)
{
triangleClipped(clippedTriangles[t], shader.varying_tri, shader, frame, &zbuffer[0], segmentationMaskBufferPtr, renderData.m_viewportMatrix, renderData.m_objectIndex);
}
}
else
{
triangle(shader.varying_tri, shader, frame, &zbuffer[0], segmentationMaskBufferPtr, renderData.m_viewportMatrix, renderData.m_objectIndex);
}
}
}
}
void TinyRenderer::renderObjectDepth(TinyRenderObjectData& renderData)
{
int width = renderData.m_rgbColorBuffer.get_width();
int height = renderData.m_rgbColorBuffer.get_height();
Vec3f light_dir_local = Vec3f(renderData.m_lightDirWorld[0],renderData.m_lightDirWorld[1],renderData.m_lightDirWorld[2]);
float light_distance = renderData.m_lightDistance;
Model* model = renderData.m_model;
if (0==model)
return;
renderData.m_viewportMatrix = viewport(0,0,width, height);
float* shadowBufferPtr = (renderData.m_shadowBuffer && renderData.m_shadowBuffer->size())?&renderData.m_shadowBuffer->at(0):0;
int* segmentationMaskBufferPtr = 0;
TGAImage depthFrame(width, height, TGAImage::RGB);
{
// light target is set to be the origin, and the up direction is set to be vertical up.
Matrix lightViewMatrix = lookat(light_dir_local*light_distance, Vec3f(0.0,0.0,0.0), Vec3f(0.0,0.0,1.0));
Matrix lightModelViewMatrix = lightViewMatrix*renderData.m_modelMatrix;
Matrix lightViewProjectionMatrix = renderData.m_projectionMatrix;
Vec3f localScaling(renderData.m_localScaling[0],renderData.m_localScaling[1],renderData.m_localScaling[2]);
DepthShader shader(model, lightModelViewMatrix, lightViewProjectionMatrix,renderData.m_modelMatrix, localScaling, light_distance);
for (int i=0; i<model->nfaces(); i++)
{
for (int j=0; j<3; j++) {
shader.vertex(i, j);
}
mat<4,3,float> stackTris[3];
b3AlignedObjectArray< mat<4,3,float> > clippedTriangles;
clippedTriangles.initializeFromBuffer(stackTris,0,3);
bool hasClipped = clipTriangleAgainstNearplane(shader.varying_tri,clippedTriangles);
if (hasClipped)
{
for (int t=0;t<clippedTriangles.size();t++)
{
triangleClipped(clippedTriangles[t], shader.varying_tri, shader, depthFrame, shadowBufferPtr, segmentationMaskBufferPtr, renderData.m_viewportMatrix, renderData.m_objectIndex);
}
} else
{
triangle(shader.varying_tri, shader, depthFrame, shadowBufferPtr, segmentationMaskBufferPtr, renderData.m_viewportMatrix, renderData.m_objectIndex);
}
}
}
}

View File

@@ -140,6 +140,13 @@ void Model::load_texture(std::string filename, const char *suffix, TGAImage &img
TGAColor Model::diffuse(Vec2f uvf) {
if (diffusemap_.get_width() && diffusemap_.get_height())
{
double val;
// bool repeat = true;
// if (repeat)
{
uvf[0] = modf(uvf[0],&val);
uvf[1] = modf(uvf[1],&val);
}
Vec2i uv(uvf[0]*diffusemap_.get_width(), uvf[1]*diffusemap_.get_height());
return diffusemap_.get(uv[0], uv[1]);
}

View File

@@ -70,6 +70,80 @@ Vec3f barycentric(Vec2f A, Vec2f B, Vec2f C, Vec2f P) {
return Vec3f(-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)
{
triangleClipped(clipc, orgClipc,shader,image,zbuffer,0,viewPortMatrix,0);
}
void triangleClipped(mat<4,3,float> &clipc, mat<4,3,float> &orgClipc, IShader &shader, TGAImage &image, float *zbuffer, int* segmentationMaskBuffer, const Matrix& viewPortMatrix, int objectIndex)
{
mat<3,4,float> screenSpacePts = (viewPortMatrix*clipc).transpose(); // transposed to ease access to each of the points
mat<3,2,float> pts2;
for (int i=0; i<3; i++)
{
pts2[i] = proj<2>(screenSpacePts[i]/screenSpacePts[i][3]);
}
Vec2f bboxmin( std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
Vec2f bboxmax(-std::numeric_limits<float>::max(), -std::numeric_limits<float>::max());
Vec2f clamp(image.get_width()-1, image.get_height()-1);
for (int i=0; i<3; i++) {
for (int j=0; j<2; j++) {
bboxmin[j] = b3Max(0.f, b3Min(bboxmin[j], pts2[i][j]));
bboxmax[j] = b3Min(clamp[j], b3Max(bboxmax[j], pts2[i][j]));
}
}
Vec2i P;
TGAColor color;
mat<3,4,float> orgScreenSpacePts = (viewPortMatrix*orgClipc).transpose(); // transposed to ease access to each of the points
mat<3,2,float> orgPts2;
for (int i=0; i<3; i++)
{
orgPts2[i] = proj<2>(orgScreenSpacePts[i]/orgScreenSpacePts[i][3]);
}
for (P.x=bboxmin.x; P.x<=bboxmax.x; P.x++) {
for (P.y=bboxmin.y; P.y<=bboxmax.y; P.y++)
{
float 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]);
bc_clip = bc_clip/(bc_clip.x+bc_clip.y+bc_clip.z);
frag_depth = -1*(clipc[2]*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]);
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);
if (!discard) {
zbuffer[P.x+P.y*image.get_width()] = frag_depth;
if (segmentationMaskBuffer)
{
segmentationMaskBuffer[P.x+P.y*image.get_width()] = objectIndex;
}
image.set(P.x, P.y, color);
}
}
}
}
void triangle(mat<4,3,float> &clipc, IShader &shader, TGAImage &image, float *zbuffer, const Matrix& viewPortMatrix)
{
triangle(clipc,shader,image,zbuffer,0,viewPortMatrix,0);
@@ -78,9 +152,7 @@ void triangle(mat<4,3,float> &clipc, IShader &shader, TGAImage &image, float *zb
void triangle(mat<4,3,float> &clipc, IShader &shader, TGAImage &image, float *zbuffer, int* segmentationMaskBuffer, const Matrix& viewPortMatrix, int objectIndex) {
mat<3,4,float> pts = (viewPortMatrix*clipc).transpose(); // transposed to ease access to each of the points
//we don't clip triangles that cross the near plane, just discard them instead of showing artifacts
if (pts[0][3]<0 || pts[1][3] <0 || pts[2][3] <0)
return;
mat<3,2,float> pts2;
for (int i=0; i<3; i++) pts2[i] = proj<2>(pts[i]/pts[i][3]);
@@ -119,4 +191,3 @@ void triangle(mat<4,3,float> &clipc, IShader &shader, TGAImage &image, float *zb
}
}
}

View File

@@ -18,5 +18,8 @@ struct IShader {
void triangle(mat<4,3,float> &pts, IShader &shader, TGAImage &image, float *zbuffer, const Matrix& viewPortMatrix);
void triangle(mat<4,3,float> &pts, IShader &shader, TGAImage &image, float *zbuffer, int* segmentationMaskBuffer, const Matrix& viewPortMatrix, int objectIndex);
void triangleClipped(mat<4,3,float> &clippedPts, mat<4,3,float> &pts, IShader &shader, TGAImage &image, float *zbuffer, const Matrix& viewPortMatrix);
void triangleClipped(mat<4,3,float> &clippedPts, mat<4,3,float> &pts, IShader &shader, TGAImage &image, float *zbuffer, int* segmentationMaskBuffer, const Matrix& viewPortMatrix, int objectIndex);
#endif //__OUR_GL_H__