From a5669d2ffdb5511a6cb85d99c5cc3f493b385290 Mon Sep 17 00:00:00 2001 From: erwin coumans Date: Wed, 5 Aug 2015 19:03:27 -0700 Subject: [PATCH] add a textured sphere8.obj test with obj loader fix shaders, so that shadowed and non-shadowed are matching fix registerGraphicsUnitSphereShape API (level of detail), support textured sphere too add support for textured cube add start for a Tutorial.cpp --- build3/stringifyShaders.bat | 20 +- data/multibody.bullet | Bin 16432 -> 14356 bytes data/slope.bullet | Bin 79960 -> 77316 bytes data/sphere8.mtl | 7 + data/sphere8.obj | 1695 +++++++++++++++++ data/uvmap.png | Bin 0 -> 41155 bytes .../CommonGraphicsAppInterface.h | 13 +- .../CommonInterfaces/CommonRenderInterface.h | 2 +- .../CommonInterfaces/CommonRigidBodyBase.h | 4 +- examples/ExampleBrowser/ExampleEntries.cpp | 6 +- .../ExampleBrowser/OpenGLExampleBrowser.cpp | 2 +- examples/ExampleBrowser/premake4.lua | 1 + .../ImportObjDemo/ImportObjExample.cpp | 47 +- .../Wavefront2GLInstanceGraphicsShape.cpp | 34 +- .../OpenGLWindow/GLInstancingRenderer.cpp | 9 + .../OpenGLWindow/Shaders/instancingPS.glsl | 2 +- examples/OpenGLWindow/Shaders/instancingPS.h | 2 +- .../OpenGLWindow/Shaders/instancingVS.glsl | 19 +- examples/OpenGLWindow/Shaders/instancingVS.h | 18 +- .../Shaders/useShadowMapInstancingPS.glsl | 15 +- .../Shaders/useShadowMapInstancingPS.h | 15 +- .../Shaders/useShadowMapInstancingVS.glsl | 4 +- .../Shaders/useShadowMapInstancingVS.h | 4 +- examples/OpenGLWindow/SimpleOpenGL2App.h | 4 +- examples/OpenGLWindow/SimpleOpenGL2Renderer.h | 4 + examples/OpenGLWindow/SimpleOpenGL3App.cpp | 58 +- examples/OpenGLWindow/SimpleOpenGL3App.h | 4 +- examples/Tutorial/Tutorial.cpp | 248 +++ examples/Tutorial/Tutorial.h | 6 + 29 files changed, 2138 insertions(+), 105 deletions(-) create mode 100644 data/sphere8.mtl create mode 100644 data/sphere8.obj create mode 100644 data/uvmap.png create mode 100644 examples/Tutorial/Tutorial.cpp create mode 100644 examples/Tutorial/Tutorial.h diff --git a/build3/stringifyShaders.bat b/build3/stringifyShaders.bat index 4d4b7ed88..9727bc0ac 100644 --- a/build3/stringifyShaders.bat +++ b/build3/stringifyShaders.bat @@ -2,16 +2,16 @@ rem @echo off -premake4 --file=stringifyKernel.lua --kernelfile="../btgui/OpenGLWindow/Shaders/instancingVS.glsl" --headerfile="../btgui/OpenGLWindow/Shaders/instancingVS.h" --stringname="instancingVertexShader" stringify -premake4 --file=stringifyKernel.lua --kernelfile="../btgui/OpenGLWindow/Shaders/instancingPS.glsl" --headerfile="../btgui/OpenGLWindow/Shaders/instancingPS.h" --stringname="instancingFragmentShader" stringify -premake4 --file=stringifyKernel.lua --kernelfile="../btgui/OpenGLWindow/Shaders/pointSpriteVS.glsl" --headerfile="../btgui/OpenGLWindow/Shaders/pointSpriteVS.h" --stringname="pointSpriteVertexShader" stringify -premake4 --file=stringifyKernel.lua --kernelfile="../btgui/OpenGLWindow/Shaders/pointSpritePS.glsl" --headerfile="../btgui/OpenGLWindow/Shaders/pointSpritePS.h" --stringname="pointSpriteFragmentShader" stringify -premake4 --file=stringifyKernel.lua --kernelfile="../btgui/OpenGLWindow/Shaders/createShadowMapInstancingPS.glsl" --headerfile="../btgui/OpenGLWindow/Shaders/createShadowMapInstancingPS.h" --stringname="createShadowMapInstancingFragmentShader" stringify -premake4 --file=stringifyKernel.lua --kernelfile="../btgui/OpenGLWindow/Shaders/createShadowMapInstancingVS.glsl" --headerfile="../btgui/OpenGLWindow/Shaders/createShadowMapInstancingVS.h" --stringname="createShadowMapInstancingVertexShader" stringify -premake4 --file=stringifyKernel.lua --kernelfile="../btgui/OpenGLWindow/Shaders/useShadowMapInstancingPS.glsl" --headerfile="../btgui/OpenGLWindow/Shaders/useShadowMapInstancingPS.h" --stringname="useShadowMapInstancingFragmentShader" stringify -premake4 --file=stringifyKernel.lua --kernelfile="../btgui/OpenGLWindow/Shaders/useShadowMapInstancingVS.glsl" --headerfile="../btgui/OpenGLWindow/Shaders/useShadowMapInstancingVS.h" --stringname="useShadowMapInstancingVertexShader" stringify -premake4 --file=stringifyKernel.lua --kernelfile="../btgui/OpenGLWindow/Shaders/linesVS.glsl" --headerfile="../btgui/OpenGLWindow/Shaders/linesVS.h" --stringname="linesVertexShader" stringify -premake4 --file=stringifyKernel.lua --kernelfile="../btgui/OpenGLWindow/Shaders/linesPS.glsl" --headerfile="../btgui/OpenGLWindow/Shaders/linesPS.h" --stringname="linesFragmentShader" stringify +premake4 --file=stringifyKernel.lua --kernelfile="../examples/OpenGLWindow/Shaders/instancingVS.glsl" --headerfile="../examples/OpenGLWindow/Shaders/instancingVS.h" --stringname="instancingVertexShader" stringify +premake4 --file=stringifyKernel.lua --kernelfile="../examples/OpenGLWindow/Shaders/instancingPS.glsl" --headerfile="../examples/OpenGLWindow/Shaders/instancingPS.h" --stringname="instancingFragmentShader" stringify +premake4 --file=stringifyKernel.lua --kernelfile="../examples/OpenGLWindow/Shaders/pointSpriteVS.glsl" --headerfile="../examples/OpenGLWindow/Shaders/pointSpriteVS.h" --stringname="pointSpriteVertexShader" stringify +premake4 --file=stringifyKernel.lua --kernelfile="../examples/OpenGLWindow/Shaders/pointSpritePS.glsl" --headerfile="../examples/OpenGLWindow/Shaders/pointSpritePS.h" --stringname="pointSpriteFragmentShader" stringify +premake4 --file=stringifyKernel.lua --kernelfile="../examples/OpenGLWindow/Shaders/createShadowMapInstancingPS.glsl" --headerfile="../examples/OpenGLWindow/Shaders/createShadowMapInstancingPS.h" --stringname="createShadowMapInstancingFragmentShader" stringify +premake4 --file=stringifyKernel.lua --kernelfile="../examples/OpenGLWindow/Shaders/createShadowMapInstancingVS.glsl" --headerfile="../examples/OpenGLWindow/Shaders/createShadowMapInstancingVS.h" --stringname="createShadowMapInstancingVertexShader" stringify +premake4 --file=stringifyKernel.lua --kernelfile="../examples/OpenGLWindow/Shaders/useShadowMapInstancingPS.glsl" --headerfile="../examples/OpenGLWindow/Shaders/useShadowMapInstancingPS.h" --stringname="useShadowMapInstancingFragmentShader" stringify +premake4 --file=stringifyKernel.lua --kernelfile="../examples/OpenGLWindow/Shaders/useShadowMapInstancingVS.glsl" --headerfile="../examples/OpenGLWindow/Shaders/useShadowMapInstancingVS.h" --stringname="useShadowMapInstancingVertexShader" stringify +premake4 --file=stringifyKernel.lua --kernelfile="../examples/OpenGLWindow/Shaders/linesVS.glsl" --headerfile="../examples/OpenGLWindow/Shaders/linesVS.h" --stringname="linesVertexShader" stringify +premake4 --file=stringifyKernel.lua --kernelfile="../examples/OpenGLWindow/Shaders/linesPS.glsl" --headerfile="../examples/OpenGLWindow/Shaders/linesPS.h" --stringname="linesFragmentShader" stringify diff --git a/data/multibody.bullet b/data/multibody.bullet index 9262fb2b345dd76d269664199df1726836a0f35f..55457695abe84c9df87461d4ba44189072314525 100644 GIT binary patch delta 1465 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 delta 8332 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

`$u_0pZ&H?60Sb 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::DBG_DrawWireframe); - const char* fileName = "samurai_monastry.obj"; + const char* fileName = "sphere8.obj"; char relativeFileName[1024]; if (b3ResourcePath::findResourcePath(fileName, relativeFileName, 1024)) { @@ -86,10 +86,49 @@ void ImportObjSetup::initPhysics() btVector3 position = trans.getOrigin(); btQuaternion orn = trans.getRotation(); - btVector3 color(0,0,1); + btVector3 color(1,1,1); + int textureIndex = -1; + //try to load some texture + for (int i=0;i0) + { + + int width,height,n; + const char* filename = shape.material.diffuse_texname.c_str(); + const unsigned char* image=0; - int shapeId = m_guiHelper->getRenderInterface()->registerShape(&gfxShape->m_vertices->at(0).xyzw[0], gfxShape->m_numvertices, &gfxShape->m_indices->at(0), gfxShape->m_numIndices); + const char* prefix[]={"./","./data/","../data/","../../data/","../../../data/","../../../../data/"}; + int numprefix = sizeof(prefix)/sizeof(const char*); + + for (int i=0;!image && igetRenderInterface()->registerTexture(image,width,height); + if (textureIndex>=0) + { + break; + } + } + + } + + } + + if (1) + { + + } + + int shapeId = m_guiHelper->getRenderInterface()->registerShape(&gfxShape->m_vertices->at(0).xyzw[0], gfxShape->m_numvertices, &gfxShape->m_indices->at(0), gfxShape->m_numIndices,B3_GL_TRIANGLES,textureIndex); //int id = m_guiHelper->getRenderInterface()->registerGraphicsInstance(shapeId,position,orn,color,scaling); diff --git a/examples/Importers/ImportObjDemo/Wavefront2GLInstanceGraphicsShape.cpp b/examples/Importers/ImportObjDemo/Wavefront2GLInstanceGraphicsShape.cpp index d7d18e701..c1b417ec9 100644 --- a/examples/Importers/ImportObjDemo/Wavefront2GLInstanceGraphicsShape.cpp +++ b/examples/Importers/ImportObjDemo/Wavefront2GLInstanceGraphicsShape.cpp @@ -40,24 +40,46 @@ GLInstanceGraphicsShape* btgCreateGraphicsShapeFromWavefrontObj(std::vectortextureList[face->vertex_index[1]]->e[0]; - vtx1.uv[1] = 0.5f;//obj->textureList[face->vertex_index[1]]->e[1]; + + if (shape.mesh.texcoords.size()) + { + vtx1.uv[0] = shape.mesh.texcoords[shape.mesh.indices[f+1]*2+0]; + vtx1.uv[1] = shape.mesh.texcoords[shape.mesh.indices[f+1]*2+1]; + } else + { + vtx1.uv[0] = 0.5f; + vtx1.uv[1] = 0.5f; + } GLInstanceVertex vtx2; vtx2.xyzw[0] = shape.mesh.positions[shape.mesh.indices[f+2]*3+0]; vtx2.xyzw[1] = shape.mesh.positions[shape.mesh.indices[f+2]*3+1]; vtx2.xyzw[2] = shape.mesh.positions[shape.mesh.indices[f+2]*3+2]; vtx2.xyzw[3] = 0.f; - vtx2.uv[0] = 0.5f; - vtx2.uv[1] = 0.5f; + if (shape.mesh.texcoords.size()) + { + vtx2.uv[0] = shape.mesh.texcoords[shape.mesh.indices[f+2]*2+0]; + vtx2.uv[1] = shape.mesh.texcoords[shape.mesh.indices[f+2]*2+1]; + } else + { + vtx2.uv[0] = 0.5; + vtx2.uv[1] = 0.5; + } btVector3 v0(vtx0.xyzw[0],vtx0.xyzw[1],vtx0.xyzw[2]); diff --git a/examples/OpenGLWindow/GLInstancingRenderer.cpp b/examples/OpenGLWindow/GLInstancingRenderer.cpp index 61559443e..756fdfdf4 100644 --- a/examples/OpenGLWindow/GLInstancingRenderer.cpp +++ b/examples/OpenGLWindow/GLInstancingRenderer.cpp @@ -214,6 +214,8 @@ static GLint createShadow_depthMVP=0; static GLint ModelViewMatrix=0; static GLint ProjectionMatrix=0; +static GLint regularLightDirIn=0; + static GLint uniform_texture_diffuse = 0; @@ -688,6 +690,8 @@ void GLInstancingRenderer::InitShaders() ModelViewMatrix = glGetUniformLocation(instancingShader, "ModelViewMatrix"); ProjectionMatrix = glGetUniformLocation(instancingShader, "ProjectionMatrix"); uniform_texture_diffuse = glGetUniformLocation(instancingShader, "Diffuse"); + regularLightDirIn = glGetUniformLocation(instancingShader,"lightDirIn"); + glUseProgram(0); instancingShaderPointSprite = gltLoadShaderPair(pointSpriteVertexShader,pointSpriteFragmentShader); @@ -1559,6 +1563,11 @@ b3Assert(glGetError() ==GL_NO_ERROR); glUseProgram(instancingShader); glUniformMatrix4fv(ProjectionMatrix, 1, false, &m_data->m_projectionMatrix[0]); glUniformMatrix4fv(ModelViewMatrix, 1, false, &m_data->m_viewMatrix[0]); + + b3Vector3 gLightDir = gLightPos; + gLightDir.normalize(); + glUniform3f(regularLightDirIn,gLightDir[0],gLightDir[1],gLightDir[2]); + glUniform1i(uniform_texture_diffuse, 0); glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, indexOffset, gfxObj->m_numGraphicsInstances); break; diff --git a/examples/OpenGLWindow/Shaders/instancingPS.glsl b/examples/OpenGLWindow/Shaders/instancingPS.glsl index edb5bd9b7..fd992e5a8 100644 --- a/examples/OpenGLWindow/Shaders/instancingPS.glsl +++ b/examples/OpenGLWindow/Shaders/instancingPS.glsl @@ -26,7 +26,7 @@ void main(void) vec3 ct,cf; float intensity,at,af; intensity = max(dot(lightDir,normalize(normal)),0); - cf = intensity*vec3(1.0,1.0,1.0)+ambient; + cf = intensity*(vec3(1.0,1.0,1.0)-ambient)+ambient; af = 1.0; ct = texel.rgb; diff --git a/examples/OpenGLWindow/Shaders/instancingPS.h b/examples/OpenGLWindow/Shaders/instancingPS.h index cf52431be..a32e7b29c 100644 --- a/examples/OpenGLWindow/Shaders/instancingPS.h +++ b/examples/OpenGLWindow/Shaders/instancingPS.h @@ -23,7 +23,7 @@ static const char* instancingFragmentShader= \ " vec3 ct,cf;\n" " float intensity,at,af;\n" " intensity = max(dot(lightDir,normalize(normal)),0);\n" -" cf = intensity*vec3(1.0,1.0,1.0)+ambient;\n" +" cf = intensity*(vec3(1.0,1.0,1.0)-ambient)+ambient;\n" " af = 1.0;\n" " \n" " ct = texel.rgb;\n" diff --git a/examples/OpenGLWindow/Shaders/instancingVS.glsl b/examples/OpenGLWindow/Shaders/instancingVS.glsl index 3c0cbc683..1663f3698 100644 --- a/examples/OpenGLWindow/Shaders/instancingVS.glsl +++ b/examples/OpenGLWindow/Shaders/instancingVS.glsl @@ -13,6 +13,7 @@ layout (location = 6) in vec3 instance_scale; uniform mat4 ModelViewMatrix; uniform mat4 ProjectionMatrix; +uniform vec3 lightDirIn; out Fragment { @@ -60,17 +61,13 @@ out vec3 lightDir,normal,ambient; void main(void) { vec4 q = instance_quaternion; - ambient = vec3(0.3,.3,0.3); - - - vec4 local_normal = (quatRotate3( vertexnormal,q)); - vec3 light_pos = vec3(-0.3,0.1,0.1); - normal = local_normal.xyz;//normalize(ModelViewMatrix * local_normal).xyz; - - lightDir = normalize(light_pos);//gl_LightSource[0].position.xyz)); -// lightDir = normalize(vec3(gl_LightSource[0].position)); - - vec4 axis = vec4(1,1,1,0); + ambient = vec3(0.6,.6,0.6); + + vec4 worldNormal = (quatRotate3( vertexnormal,q)); + normal = normalize(worldNormal).xyz; + + lightDir = lightDirIn; + vec4 localcoord = quatRotate3( position.xyz*instance_scale,q); vec4 vertexPos = ProjectionMatrix * ModelViewMatrix *(instance_position+localcoord); diff --git a/examples/OpenGLWindow/Shaders/instancingVS.h b/examples/OpenGLWindow/Shaders/instancingVS.h index 94abae198..563d22127 100644 --- a/examples/OpenGLWindow/Shaders/instancingVS.h +++ b/examples/OpenGLWindow/Shaders/instancingVS.h @@ -11,6 +11,7 @@ static const char* instancingVertexShader= \ "layout (location = 6) in vec3 instance_scale;\n" "uniform mat4 ModelViewMatrix;\n" "uniform mat4 ProjectionMatrix;\n" +"uniform vec3 lightDirIn;\n" "out Fragment\n" "{\n" " vec4 color;\n" @@ -51,16 +52,13 @@ static const char* instancingVertexShader= \ "void main(void)\n" "{\n" " vec4 q = instance_quaternion;\n" -" ambient = vec3(0.3,.3,0.3);\n" -" \n" -" \n" -" vec4 local_normal = (quatRotate3( vertexnormal,q));\n" -" vec3 light_pos = vec3(-0.3,0.1,0.1);\n" -" normal = local_normal.xyz;//normalize(ModelViewMatrix * local_normal).xyz;\n" -" lightDir = normalize(light_pos);//gl_LightSource[0].position.xyz));\n" -"// lightDir = normalize(vec3(gl_LightSource[0].position));\n" -" \n" -" vec4 axis = vec4(1,1,1,0);\n" +" ambient = vec3(0.6,.6,0.6);\n" +" \n" +" vec4 worldNormal = (quatRotate3( vertexnormal,q));\n" +" normal = normalize(worldNormal).xyz;\n" +" \n" +" lightDir = lightDirIn;\n" +" \n" " vec4 localcoord = quatRotate3( position.xyz*instance_scale,q);\n" " vec4 vertexPos = ProjectionMatrix * ModelViewMatrix *(instance_position+localcoord);\n" " gl_Position = vertexPos;\n" diff --git a/examples/OpenGLWindow/Shaders/useShadowMapInstancingPS.glsl b/examples/OpenGLWindow/Shaders/useShadowMapInstancingPS.glsl index c4913d702..cd780fbea 100644 --- a/examples/OpenGLWindow/Shaders/useShadowMapInstancingPS.glsl +++ b/examples/OpenGLWindow/Shaders/useShadowMapInstancingPS.glsl @@ -23,13 +23,13 @@ out vec4 color; void main(void) { - vec4 texel = fragment.color*texture(Diffuse,vert.texcoord);//fragment.color; + vec4 texel = fragment.color*texture(Diffuse,vert.texcoord); vec3 ct,cf; float intensity,at,af; intensity = clamp( dot( normalize(normal),lightDir ), 0,1 ); - cf = ambient; + af = 1.0; ct = texel.rgb; @@ -43,14 +43,9 @@ void main(void) float visibility = texture(shadowMap, vec3(ShadowCoord.xy,(ShadowCoord.z-bias)/ShadowCoord.w)); - intensity*=2; - if (intensity>1) - intensity=1.f; + intensity = 0.7*intensity + 0.3*intensity*visibility; - visibility *= intensity; - - if (visibility<0.6) - visibility=0.6f; + cf = intensity*(vec3(1.0,1.0,1.0)-ambient)+ambient; - color = vec4(ct * visibility, fragment.color.w); + color = vec4(ct * cf, fragment.color.w); } diff --git a/examples/OpenGLWindow/Shaders/useShadowMapInstancingPS.h b/examples/OpenGLWindow/Shaders/useShadowMapInstancingPS.h index d43ec5dcb..0550ff58a 100644 --- a/examples/OpenGLWindow/Shaders/useShadowMapInstancingPS.h +++ b/examples/OpenGLWindow/Shaders/useShadowMapInstancingPS.h @@ -17,13 +17,13 @@ static const char* useShadowMapInstancingFragmentShader= \ "out vec4 color;\n" "void main(void)\n" "{\n" -" vec4 texel = fragment.color*texture(Diffuse,vert.texcoord);//fragment.color;\n" +" vec4 texel = fragment.color*texture(Diffuse,vert.texcoord);\n" " vec3 ct,cf;\n" " float intensity,at,af;\n" " \n" " intensity = clamp( dot( normalize(normal),lightDir ), 0,1 );\n" " \n" -" cf = ambient;\n" +" \n" " af = 1.0;\n" " \n" " ct = texel.rgb;\n" @@ -35,15 +35,10 @@ static const char* useShadowMapInstancingFragmentShader= \ " bias = clamp(bias, 0,0.01);\n" " float visibility = texture(shadowMap, vec3(ShadowCoord.xy,(ShadowCoord.z-bias)/ShadowCoord.w));\n" " \n" -" intensity*=2;\n" -" if (intensity>1)\n" -" intensity=1.f;\n" +" intensity = 0.7*intensity + 0.3*intensity*visibility;\n" " \n" -" visibility *= intensity;\n" -" \n" -" if (visibility<0.6)\n" -" visibility=0.6f;\n" +" cf = intensity*(vec3(1.0,1.0,1.0)-ambient)+ambient;\n" " \n" -" color = vec4(ct * visibility, fragment.color.w);\n" +" color = vec4(ct * cf, fragment.color.w);\n" "}\n" ; diff --git a/examples/OpenGLWindow/Shaders/useShadowMapInstancingVS.glsl b/examples/OpenGLWindow/Shaders/useShadowMapInstancingVS.glsl index fe16aaf4c..9de5c0aa5 100644 --- a/examples/OpenGLWindow/Shaders/useShadowMapInstancingVS.glsl +++ b/examples/OpenGLWindow/Shaders/useShadowMapInstancingVS.glsl @@ -65,7 +65,7 @@ out vec3 lightDir,normal,ambient; void main(void) { vec4 q = instance_quaternion; - ambient = vec3(0.3,.3,0.3); + ambient = vec3(0.6,.6,0.6); vec4 worldNormal = (quatRotate3( vertexnormal,q)); @@ -73,7 +73,7 @@ void main(void) lightDir = lightDirIn; - vec4 axis = vec4(1,1,1,0); + vec4 localcoord = quatRotate3( position.xyz*instance_scale,q); vec4 vertexPos = MVP* vec4((instance_position+localcoord).xyz,1); diff --git a/examples/OpenGLWindow/Shaders/useShadowMapInstancingVS.h b/examples/OpenGLWindow/Shaders/useShadowMapInstancingVS.h index 8c2ee8765..e52ec62ee 100644 --- a/examples/OpenGLWindow/Shaders/useShadowMapInstancingVS.h +++ b/examples/OpenGLWindow/Shaders/useShadowMapInstancingVS.h @@ -55,14 +55,14 @@ static const char* useShadowMapInstancingVertexShader= \ "void main(void)\n" "{\n" " vec4 q = instance_quaternion;\n" -" ambient = vec3(0.3,.3,0.3);\n" +" ambient = vec3(0.6,.6,0.6);\n" " \n" " vec4 worldNormal = (quatRotate3( vertexnormal,q));\n" " \n" " normal = normalize(worldNormal).xyz;\n" " lightDir = lightDirIn;\n" " \n" -" vec4 axis = vec4(1,1,1,0);\n" +" \n" " vec4 localcoord = quatRotate3( position.xyz*instance_scale,q);\n" " vec4 vertexPos = MVP* vec4((instance_position+localcoord).xyz,1);\n" " gl_Position = vertexPos;\n" diff --git a/examples/OpenGLWindow/SimpleOpenGL2App.h b/examples/OpenGLWindow/SimpleOpenGL2App.h index 23af2e09b..26fb2468b 100644 --- a/examples/OpenGLWindow/SimpleOpenGL2App.h +++ b/examples/OpenGLWindow/SimpleOpenGL2App.h @@ -19,11 +19,11 @@ public: virtual void swapBuffer(); virtual void drawText( const char* txt, int posX, int posY); virtual void setBackgroundColor(float red, float green, float blue); - virtual int registerCubeShape(float halfExtentsX,float halfExtentsY, float halfExtentsZ) + virtual int registerCubeShape(float halfExtentsX,float halfExtentsY, float halfExtentsZ, int textureIndex = -1) { return 0; } - virtual int registerGraphicsSphereShape(float radius, bool usePointSprites, int largeSphereThreshold, int mediumSphereThreshold) + virtual int registerGraphicsUnitSphereShape(EnumSphereLevelOfDetail lod, int textureId=-1) { return 0; } diff --git a/examples/OpenGLWindow/SimpleOpenGL2Renderer.h b/examples/OpenGLWindow/SimpleOpenGL2Renderer.h index c92c529a9..45c7809da 100644 --- a/examples/OpenGLWindow/SimpleOpenGL2Renderer.h +++ b/examples/OpenGLWindow/SimpleOpenGL2Renderer.h @@ -46,6 +46,10 @@ struct SimpleOpenGL2Renderer : public CommonRenderInterface { return m_height; } + virtual int registerTexture(const unsigned char* texels, int width, int height) + { + return -1; + } virtual int registerGraphicsInstance(int shapeIndex, const double* position, const double* quaternion, const double* color, const double* scaling); virtual int registerGraphicsInstance(int shapeIndex, const float* position, const float* quaternion, const float* color, const float* scaling); diff --git a/examples/OpenGLWindow/SimpleOpenGL3App.cpp b/examples/OpenGLWindow/SimpleOpenGL3App.cpp index 792ca8438..a5fda66ba 100644 --- a/examples/OpenGLWindow/SimpleOpenGL3App.cpp +++ b/examples/OpenGLWindow/SimpleOpenGL3App.cpp @@ -419,7 +419,7 @@ struct GfxVertex float u,v; }; -int SimpleOpenGL3App::registerCubeShape(float halfExtentsX,float halfExtentsY, float halfExtentsZ) +int SimpleOpenGL3App::registerCubeShape(float halfExtentsX,float halfExtentsY, float halfExtentsZ, int textureIndex) { @@ -442,7 +442,7 @@ int SimpleOpenGL3App::registerCubeShape(float halfExtentsX,float halfExtentsY, f verts[i].v = cube_vertices[i*9+8]; } - int shapeId = m_instancingRenderer->registerShape(&verts[0].x,numVertices,cube_indices,numIndices); + int shapeId = m_instancingRenderer->registerShape(&verts[0].x,numVertices,cube_indices,numIndices,B3_GL_TRIANGLES,textureIndex); return shapeId; } @@ -480,42 +480,46 @@ void SimpleOpenGL3App::registerGrid(int cells_x, int cells_z, float color0[4], f } - -int SimpleOpenGL3App::registerGraphicsSphereShape(float radius, bool usePointSprites, int largeSphereThreshold, int mediumSphereThreshold) +int SimpleOpenGL3App::registerGraphicsUnitSphereShape(EnumSphereLevelOfDetail lod, int textureId) { int strideInBytes = 9*sizeof(float); int graphicsShapeIndex = -1; - if (radius>=largeSphereThreshold) + switch (lod) { - int numVertices = sizeof(detailed_sphere_vertices)/strideInBytes; - int numIndices = sizeof(detailed_sphere_indices)/sizeof(int); - graphicsShapeIndex = m_instancingRenderer->registerShape(&detailed_sphere_vertices[0],numVertices,detailed_sphere_indices,numIndices); - } else - { - - if (usePointSprites) + case SPHERE_LOD_POINT_SPRITE: { int numVertices = sizeof(point_sphere_vertices)/strideInBytes; int numIndices = sizeof(point_sphere_indices)/sizeof(int); - graphicsShapeIndex = m_instancingRenderer->registerShape(&point_sphere_vertices[0],numVertices,point_sphere_indices,numIndices,B3_GL_POINTS); - } else - { - if (radius>=mediumSphereThreshold) - { - int numVertices = sizeof(medium_sphere_vertices)/strideInBytes; - int numIndices = sizeof(medium_sphere_indices)/sizeof(int); - graphicsShapeIndex = m_instancingRenderer->registerShape(&medium_sphere_vertices[0],numVertices,medium_sphere_indices,numIndices); - } else - { - int numVertices = sizeof(low_sphere_vertices)/strideInBytes; - int numIndices = sizeof(low_sphere_indices)/sizeof(int); - graphicsShapeIndex = m_instancingRenderer->registerShape(&low_sphere_vertices[0],numVertices,low_sphere_indices,numIndices); - } + graphicsShapeIndex = m_instancingRenderer->registerShape(&point_sphere_vertices[0],numVertices,point_sphere_indices,numIndices,B3_GL_POINTS,textureId); + break; } - } + + case SPHERE_LOD_LOW: + { + int numVertices = sizeof(low_sphere_vertices)/strideInBytes; + int numIndices = sizeof(low_sphere_indices)/sizeof(int); + graphicsShapeIndex = m_instancingRenderer->registerShape(&low_sphere_vertices[0],numVertices,low_sphere_indices,numIndices,B3_GL_TRIANGLES,textureId); + break; + } + case SPHERE_LOD_MEDIUM: + { + int numVertices = sizeof(medium_sphere_vertices)/strideInBytes; + int numIndices = sizeof(medium_sphere_indices)/sizeof(int); + graphicsShapeIndex = m_instancingRenderer->registerShape(&medium_sphere_vertices[0],numVertices,medium_sphere_indices,numIndices,B3_GL_TRIANGLES,textureId); + break; + } + case SPHERE_LOD_HIGH: + default: + { + int numVertices = sizeof(detailed_sphere_vertices)/strideInBytes; + int numIndices = sizeof(detailed_sphere_indices)/sizeof(int); + graphicsShapeIndex = m_instancingRenderer->registerShape(&detailed_sphere_vertices[0],numVertices,detailed_sphere_indices,numIndices,B3_GL_TRIANGLES,textureId); + break; + } + }; return graphicsShapeIndex; } diff --git a/examples/OpenGLWindow/SimpleOpenGL3App.h b/examples/OpenGLWindow/SimpleOpenGL3App.h index 10cbd8f6f..64123c36e 100644 --- a/examples/OpenGLWindow/SimpleOpenGL3App.h +++ b/examples/OpenGLWindow/SimpleOpenGL3App.h @@ -19,8 +19,8 @@ struct SimpleOpenGL3App : public CommonGraphicsApp SimpleOpenGL3App(const char* title, int width,int height); virtual ~SimpleOpenGL3App(); - virtual int registerCubeShape(float halfExtentsX=1.f,float halfExtentsY=1.f, float halfExtentsZ = 1.f); - virtual int registerGraphicsSphereShape(float radius, bool usePointSprites=true, int largeSphereThreshold=100, int mediumSphereThreshold=10); + virtual int registerCubeShape(float halfExtentsX=1.f,float halfExtentsY=1.f, float halfExtentsZ = 1.f, int textureIndex = -1); + virtual int registerGraphicsUnitSphereShape(EnumSphereLevelOfDetail lod, int textureId=-1); virtual void registerGrid(int xres, int yres, float color0[4], float color1[4]); void dumpNextFrameToPng(const char* pngFilename); void dumpFramesToVideo(const char* mp4Filename); diff --git a/examples/Tutorial/Tutorial.cpp b/examples/Tutorial/Tutorial.cpp new file mode 100644 index 000000000..71fcdf4c4 --- /dev/null +++ b/examples/Tutorial/Tutorial.cpp @@ -0,0 +1,248 @@ + +#include "Tutorial.h" +#include "../CommonInterfaces/CommonGraphicsAppInterface.h" +#include "../CommonInterfaces/CommonRenderInterface.h" + +#include "../CommonInterfaces/CommonExampleInterface.h" +#include "LinearMath/btTransform.h" +#include "stb_image/stb_image.h" + +#include "../CommonInterfaces/CommonGUIHelperInterface.h" + +struct LWPose +{ + btVector3 m_worldPosition; + btQuaternion m_worldOrientation; + LWPose() + :m_worldPosition(0,0,0), + m_worldOrientation(0,0,0,1) + { + } + +}; + +enum LWRIGIDBODY_FLAGS +{ + LWFLAG_USE_QUATERNION_DERIVATIVE = 1, + +}; +struct LWRightBody +{ + LWPose m_worldPose; + btVector3 m_linearVelocity; + btVector3 m_angularVelocity; + + int m_graphicsIndex; + int m_flags; + + LWRightBody() + :m_linearVelocity(0,0,0), + m_angularVelocity(0,0,0), + m_flags(LWFLAG_USE_QUATERNION_DERIVATIVE) + { + + } + + void integrateTransform(double deltaTime) + { + LWPose newPose; + + newPose.m_worldPosition = m_worldPose.m_worldPosition + m_linearVelocity*deltaTime; + + if (m_flags & LWFLAG_USE_QUATERNION_DERIVATIVE) + { + newPose.m_worldOrientation = m_worldPose.m_worldOrientation; + newPose.m_worldOrientation += (m_angularVelocity * newPose.m_worldOrientation) * (deltaTime * btScalar(0.5)); + newPose.m_worldOrientation.normalize(); + m_worldPose = newPose; + } else + { + //Exponential map + //google for "Practical Parameterization of Rotations Using the Exponential Map", F. Sebastian Grassia + + btVector3 axis; + btScalar fAngle = m_angularVelocity.length(); + //limit the angular motion + const btScalar angularMotionThreshold = btScalar(0.5)*SIMD_HALF_PI; + + if (fAngle*deltaTime > angularMotionThreshold) + { + fAngle = angularMotionThreshold / deltaTime; + } + + if ( fAngle < btScalar(0.001) ) + { + // use Taylor's expansions of sync function + axis = m_angularVelocity*( btScalar(0.5)*deltaTime-(deltaTime*deltaTime*deltaTime)*(btScalar(0.020833333333))*fAngle*fAngle ); + } + else + { + // sync(fAngle) = sin(c*fAngle)/t + axis = m_angularVelocity*( btSin(btScalar(0.5)*fAngle*deltaTime)/fAngle ); + } + btQuaternion dorn (axis.x(),axis.y(),axis.z(),btCos( fAngle*deltaTime*btScalar(0.5) )); + btQuaternion orn0 = m_worldPose.m_worldOrientation; + + btQuaternion predictedOrn = dorn * orn0; + predictedOrn.normalize(); + m_worldPose.m_worldOrientation = predictedOrn; + } + } + + + void stepSimulation(double deltaTime) + { + integrateTransform(deltaTime); + } +}; + + + +///quick demo showing the right-handed coordinate system and positive rotations around each axis +class Tutorial : public CommonExampleInterface +{ + CommonGraphicsApp* m_app; + float m_x; + float m_y; + float m_z; + int m_tutorialIndex; + + LWRightBody* m_body; + +public: + + Tutorial(CommonGraphicsApp* app, int tutorialIndex) + :m_app(app), + m_x(0), + m_y(0), + m_z(0), + m_tutorialIndex(tutorialIndex) + { + m_app->setUpAxis(2); + + + { + + int boxId = m_app->registerCubeShape(100,100,1); + btVector3 pos(0,0,-1); + btQuaternion orn(0,0,0,1); + btVector4 color(1,1,1,1); + btVector3 scaling(1,1,1); + m_app->m_renderer->registerGraphicsInstance(boxId,pos,orn,color,scaling); + } + + m_body = new LWRightBody(); + m_body->m_worldPose.m_worldPosition.setValue(0,0,3); + + { + int textureIndex = -1; + + if (1) + { + int width,height,n; + + const char* filename = "data/cube.png"; + const unsigned char* image=0; + + const char* prefix[]={"./","../","../../","../../../","../../../../"}; + int numprefix = sizeof(prefix)/sizeof(const char*); + + for (int i=0;!image && im_renderer->registerTexture(image,width,height); + } + } + + int boxId = m_app->registerCubeShape(1,1,1,textureIndex);//>registerGraphicsUnitSphereShape(SPHERE_LOD_HIGH, textureIndex); + btVector4 color(1,1,1,1); + btVector3 scaling(1,1,1); + m_body->m_graphicsIndex = m_app->m_renderer->registerGraphicsInstance(boxId,m_body->m_worldPose.m_worldPosition, m_body->m_worldPose.m_worldOrientation,color,scaling); + m_app->m_renderer->writeSingleInstanceTransformToCPU(m_body->m_worldPose.m_worldPosition, m_body->m_worldPose.m_worldOrientation, m_body->m_graphicsIndex); + } + + m_app->m_renderer->writeTransforms(); + } + virtual ~Tutorial() + { + m_app->m_renderer->enableBlend(false); + } + + + virtual void initPhysics() + { + } + virtual void exitPhysics() + { + + } + virtual void stepSimulation(float deltaTime) + { + m_x+=0.01f; + m_y+=0.01f; + m_z+=0.01f; + //m_body->m_worldPose.m_worldPosition+= btVector3(0,0.01,0); + //m_body->m_linearVelocity=btVector3(0,0.1,0); + m_body->m_angularVelocity =btVector3(0,0.1,0); + m_body->integrateTransform(deltaTime); + + m_app->m_renderer->writeSingleInstanceTransformToCPU(m_body->m_worldPose.m_worldPosition, m_body->m_worldPose.m_worldOrientation, m_body->m_graphicsIndex); + m_app->m_renderer->writeTransforms(); + } + virtual void renderScene() + { + m_app->m_renderer->renderScene(); + m_app->drawText3D("X",1,0,0,1); + m_app->drawText3D("Y",0,1,0,1); + m_app->drawText3D("Z",0,0,1,1); + } + + + + virtual void physicsDebugDraw(int debugDrawFlags) + { + + + } + virtual bool mouseMoveCallback(float x,float y) + { + return false; + } + virtual bool mouseButtonCallback(int button, int state, float x, float y) + { + return false; + } + virtual bool keyboardCallback(int key, int state) + { + return false; + } + + + virtual void resetCamera() + { + float dist = 3.5; + float pitch = 136; + float yaw = 32; + float targetPos[3]={0,0,0}; + if (m_app->m_renderer && m_app->m_renderer->getActiveCamera()) + { + m_app->m_renderer->getActiveCamera()->setCameraDistance(dist); + m_app->m_renderer->getActiveCamera()->setCameraPitch(pitch); + m_app->m_renderer->getActiveCamera()->setCameraYaw(yaw); + m_app->m_renderer->getActiveCamera()->setCameraTargetPosition(targetPos[0],targetPos[1],targetPos[2]); + } + } +}; + +class CommonExampleInterface* TutorialCreateFunc(struct CommonExampleOptions& options) +{ + return new Tutorial(options.m_guiHelper->getAppInterface(), options.m_option); +} + diff --git a/examples/Tutorial/Tutorial.h b/examples/Tutorial/Tutorial.h new file mode 100644 index 000000000..fb93e6c76 --- /dev/null +++ b/examples/Tutorial/Tutorial.h @@ -0,0 +1,6 @@ +#ifndef TUTORIAL_H +#define TUTORIAL_H + +class CommonExampleInterface* TutorialCreateFunc(struct CommonExampleOptions& options); + +#endif //TUTORIAL_H