/** * Configure the light source used for shadow mapping * * @param lightNodeInstance The node containing the light instance * @param lightIndex The index of the light in light instances of the node */ public void setLight(final Node lightNodeInstance, final int lightIndex) { // android.util.Log.d(TAG,"setLight("+lightNodeInstance.id+","+lightIndex+")"); this.lightType = lightNodeInstance.lightInstances[lightIndex].type; switch (this.lightType) { case Light.DIRECTIONAL: this.lightModel[8] = this.lightModel[8] = this.lightModel[9] = this.lightModel[11] = 0f; this.lightModel[10] = -1f; MatrixUtils.multiplyMV(this.lightModel, 8, lightNodeInstance.model, 0, this.lightModel, 8); this.lightModel[0] = this.lightModel[1] = this.lightModel[2] = 0f; this.lightModel[3] = 1f; MatrixUtils.multiplyMV(this.lightModel, 0, lightNodeInstance.model, 0, this.lightModel, 0); final float length = Matrix.length(this.lightModel[0], this.lightModel[1], this.lightModel[2]); this.lightModel[8] *= length; this.lightModel[9] *= length; this.lightModel[10] *= length; break; case Light.POINT: this.lightModel[0] = this.lightModel[1] = this.lightModel[2] = 0f; this.lightModel[3] = 1f; MatrixUtils.multiplyMV(this.lightModel, 0, lightNodeInstance.model, 0, this.lightModel, 0); break; case Light.SPOT: this.lightModel[0] = this.lightModel[1] = this.lightModel[2] = 0f; this.lightModel[3] = 1f; MatrixUtils.multiplyMV(this.lightModel, 0, lightNodeInstance.model, 0, this.lightModel, 0); this.lightModel[8] = this.lightModel[8] = this.lightModel[9] = this.lightModel[11] = 0f; this.lightModel[10] = -1f; MatrixUtils.multiplyMV(this.lightModel, 8, lightNodeInstance.model, 0, this.lightModel, 8); this.lightModel[4] = this.lightModel[0] + this.lightModel[8]; this.lightModel[5] = this.lightModel[1] + this.lightModel[9]; this.lightModel[6] = this.lightModel[2] + this.lightModel[10]; this.lightModel[7] = 1f; break; } }
/** * Simple recursive method to draw a node and its subnodes * * @param nodeInstance The node instance */ private void drawNode(Node nodeInstance) { MatrixUtils.multiplyMM(this.lightMvpCache, 48, this.lightMvpCache, 32, nodeInstance.model, 0); GLES20.glUniformMatrix4fv(this.u_lightMvpMatrixMat4Handle, 1, false, this.lightMvpCache, 48); if (nodeInstance.geometryInstances != null) { for (GeometryInstance geometryInstance : nodeInstance.geometryInstances) { for (Element element : geometryInstance.geometry.elements) { if (element.handle == GlBuffer.UNBIND_HANDLE) { GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, GlBuffer.UNBIND_HANDLE); final GlBuffer<float[]> elementBuffer = BufferUtils.elementToGlBuffer(element); elementBuffer.position(elementBuffer.chunks[0]); GLES20.glVertexAttribPointer( this.a_PositionVec4Handle, elementBuffer.chunks[0].components, elementBuffer.datatype, false, elementBuffer.stride, elementBuffer.data); GLES20.glDrawArrays(element.type, 0, element.count); elementBuffer.free(); } else { GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, element.handle); GLES20Utils.glVertexAttribPointer( this.a_PositionVec4Handle, element.inputs[0][GlAssets.Geometry.Element.SIZE], GLES20.GL_FLOAT, false, element.stride, element.inputs[0][GlAssets.Geometry.Element.OFFSET]); GLES20.glDrawArrays(element.type, 0, element.count); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, GlBuffer.UNBIND_HANDLE); } } } } if (nodeInstance.nodeInstances != null) { for (Node childNode : nodeInstance.nodeInstances) { this.drawNode(childNode); } } }
/** * Fine settings used to set the light view and projection matrixes. This method is very important * as it allows to improve greatly quality without CPU additional charge. Try to set zFar and * zNear as best as you can. A good practice is to bind a camera instance to each node instance * used as root node for shadow map generation. * * @param cameraNodeInstance The node owning the camera * @param cameraIndex The indew of the camera in the node instance */ @SuppressLint("NewApi") public void setCamera(final Node cameraNodeInstance, final int cameraIndex) { // android.util.Log.d(TAG,"setCamera("+cameraNodeInstance.id+","+cameraIndex+")"); if (cameraNodeInstance.cameraInstances[cameraIndex].type == Camera.ORTHOGRAPHIC) { Matrix.orthoM( lightMvpCache, 16, -cameraNodeInstance.cameraInstances[cameraIndex].settings[Camera.XMAG], cameraNodeInstance.cameraInstances[cameraIndex].settings[Camera.XMAG], -cameraNodeInstance.cameraInstances[cameraIndex].settings[Camera.YMAG], cameraNodeInstance.cameraInstances[cameraIndex].settings[Camera.YMAG], cameraNodeInstance.cameraInstances[cameraIndex].settings[Camera.ZNEAR], cameraNodeInstance.cameraInstances[cameraIndex].settings[Camera.ZFAR]); } else { MatrixUtils.perspectiveM( this.lightMvpCache, 16, cameraNodeInstance.cameraInstances[cameraIndex].settings[Camera.YFOV], 1, cameraNodeInstance.cameraInstances[cameraIndex].settings[Camera.ZNEAR], cameraNodeInstance.cameraInstances[cameraIndex].settings[Camera.ZFAR]); } }
/* (non-Javadoc) * @see fr.kesk.gl.shader.GlShader#render(fr.kesk.gl.GlAssets.Node) */ @Override public void render(Node nodeInstance) { // android.util.Log.d(TAG,"render("+nodeInstance.id+")"); if (this.lightType == Light.DIRECTIONAL) { this.lightModel[4] = this.lightModel[5] = this.lightModel[6] = 0f; this.lightModel[7] = 1f; MatrixUtils.multiplyMV(this.lightModel, 4, nodeInstance.model, 0, this.lightModel, 4); this.lightModel[0] = this.lightModel[4] - this.lightModel[8]; this.lightModel[1] = this.lightModel[5] - this.lightModel[9]; this.lightModel[2] = this.lightModel[6] - this.lightModel[10]; this.lightModel[3] = 1f; Matrix.setLookAtM( this.lightMvpCache, 0, this.lightModel[0], this.lightModel[1], this.lightModel[2], this.lightModel[4], this.lightModel[5], this.lightModel[6], 0f, 1f, 0f); MatrixUtils.multiplyMM(this.lightMvpCache, 32, this.lightMvpCache, 16, this.lightMvpCache, 0); MatrixUtils.multiplyMM( this.currentShadowMap.shadowMatrix, 0, GlFastShadowMapShader.BIAS_MATRIX, 0, this.lightMvpCache, 32); } else if (this.lightType == Light.POINT) { this.lightModel[4] = this.lightModel[5] = this.lightModel[6] = 0f; this.lightModel[7] = 1f; MatrixUtils.multiplyMV(this.lightModel, 4, nodeInstance.model, 0, this.lightModel, 4); Matrix.setLookAtM( this.lightMvpCache, 0, this.lightModel[0], this.lightModel[1], this.lightModel[2], this.lightModel[4], this.lightModel[5], this.lightModel[6], 0f, 1f, 0f); MatrixUtils.multiplyMM(this.lightMvpCache, 32, this.lightMvpCache, 16, this.lightMvpCache, 0); MatrixUtils.multiplyMM( this.currentShadowMap.shadowMatrix, 0, GlFastShadowMapShader.BIAS_MATRIX, 0, this.lightMvpCache, 32); } // Render the scene in the FBO this.fbo.bind(); this.program.start(); this.cullfaceMode = GlContext.glGetState(GLES20.GL_CULL_FACE_MODE); this.viewPort = GlContext.glGetState(GLES20.GL_VIEWPORT); GLES20.glCullFace(GLES20.GL_FRONT); GLES20.glViewport(0, 0, this.quality, this.quality); GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT); GLES20.glEnableVertexAttribArray(this.a_PositionVec4Handle); this.drawNode(nodeInstance); GLES20.glDisableVertexAttribArray(this.a_PositionVec4Handle); this.fbo.unbind(); GLES20.glCullFace((int) this.cullfaceMode[0]); GLES20.glViewport( (int) this.viewPort[0], (int) this.viewPort[1], (int) this.viewPort[2], (int) this.viewPort[3]); }