Jump to content
  • Advertisement

Martin Winged

  • Content Count

  • Joined

  • Last visited

Community Reputation

129 Neutral

About Martin Winged

  • Rank
  1. @JohnnyCode I'm a little bit confused now. GLSL specification states - "If an array is indexed with an expression that is not an integral constant expression, or if an array is passed as an argument to a function, then its size must be declared before any such use."   So unless I'd make a long long if-else ladder (which is strongly dissuaded on older GLSL) which would look like this: else if (matrixIndex == 1) return mat4(rawMatrices[12], rawMatrices[13], ..., rawMatrices[23], 0, 0, 0, 1); else if (matrixIndex == 2) return mat4(rawMatrices[24], rawMatrices[25], ..., rawMatrices[35], 0, 0, 0, 1); ... else if (matrixIndex == 63) return mat4(rawMatrices[756], rawMatrices[757], ..., rawMatrices[767], 0, 0, 0, 1);  I'm bound to declare it's size first, and because of this I can't really see any advantageous solution which would establish as many floats as I need (because of the fact that the amount of needed floats would dynamically change at the runtime).
  2. Sending an array of floats and saving uniform vectors slots sounds more promising to me than sending ready matrices and binding every one of them separately, so I think I'd rather go that way.   BTW Is there a way to define size of an array in the vertex shader basing on MAX_VERTEX_UNIFORM_VECTORS value, so it would be more 'cross-hardware'?
  3. @JohnnyCode I like the second method, but I'm not sure what would be more computational expensive - creating matrices from an array of vec4 on GPU or sending on each draw call filled Float32Array with let's say 32 matrices? Also I don't need to offset anything since I found a clever way of managing model matrices, so it is not a problem for now.
  4. I want to send an array of matrices (to be more specific: a dynamically changing between draw calls Float32Array of 4x4 Float32Arrays) to a vertex shader with multiple model matrices (size of this.modelMatrices depends on how many objects are moving, so there may be only one model matrix and just in the next frame there may be 30 of them).   When I just call: gl.uniformMatrix4fv(program.mMatrixUniform, false, this.modelMatrices); where this.modelMatrices is an Float32Array, and program.mMatrixUniform is declared like this: program.mMatrixUniform = gl.getUniformLocation(program, 'uMMatrix'); it throws:   In OpenGL uniformMatrix4fv there is an additional count attribute, which allows to specify the amount of matrices sent while in WebGL there isn't. Also, the question is, does dynamically changing this.modelMatrices causes a problem too?   What is a proper way of doing it in WebGL?
  5. Finally, by trial and error, I managed to get this thing working.   The problem was that the cubemap texture is mirrored, so I had to scale the regular projection matrix by (1, -1, 1) in order to un-flip it.   Also, the right vector to read cubemap is vWorldVertex.xyz - uLightPosition.   Now everything seems to be working nice!
  6. --------- --- First of all I must say, that I have read every topic on this forum describing using cubemaps, but I'm still confused about how to use them. I want to use them to achieve a simple omni-directional (point) light type shading in my WebGL application. I know that there is a lot more techniques that works better than using cubemaps (like using Two-Hemispheres or Camera Space Shadow Mapping) which are way more efficient, but for an educational purpose cubemaps are my primary goal.   --------- --- Till now, I have adapted a simple shadow mapping which works with directional lights (with one exception: I don't know how to cut off the glitchy part beyond the reach of a single shadow map texture).   --------- --- This is how I understand the workflow:   1. Initialize a TEXTURE_CUBE_MAP texture, which will contain all 6 sides of cube map.   gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.texture); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR); for (var i = 0; i < 6; i++) gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl.RGBA, this.size, this.size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);   2. Initialize 6 framebuffers, each for one rendered direction from a light's position.   for (i = 0; i < 6; i++) { this.framebuffer[i] = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer[i]); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, this.texture, 0); gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this.depthbuffer); }   3. Initialize a camera that will be suitable for shadow map rendering (90 FOV, square size).   4. Onto each of created framebuffers render the scene from the light's position looking in sequence at each direction (X, -X, Y, -Y, Z, -Z). After each shadow map render, save a current camera view matrix, which will be passed to a vertex shader just before a regular render.   var cubeMapDirections = [new vec3(1, 0, 0), new vec3(-1, 0, 0), new vec3(0, 1, 0), new vec3(0, -1, 0), new vec3(0, 0, 1), new vec3(0, 0, -1)]; for (var i = 0; i < 6; i++) { shadow.buffer.bind(i); // Bind previously created framebuffers camera.lookAt( light.position.add( cubeMapDirections[i] ) ); light.viewMatrix[i].makeInverseRigidBody(camera.local); // Translate center of the world to the camera scene.draw(shadow.program); // Draw the scene with a program that will render the depth values to a texture } --------- --- From now on, I am not sure how to adapt it to the cubemap texture and 6 view matrices.   5. Send all the matrices and all other stuff to the shaders (should I send 6 view matrices, or should I use a more clever approach?)   6. In the vertex shader, project a current vertex using light's projection and view matrix and push it into the 0.0 - 1.0 region. It will be used later to dereference the depth map (if I had sent all 6 view marices, it looks like I should now do it 6 times)   const mat4 ScaleMatrix = mat4(0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.5, 0.5, 1.0); (...) vDepthPosition = ScaleMatrix * uPMatrixFromLight * uVMatrixFromLight * vWorldVertex; 7. In fragment shader calculate the distance between the current vertex and the light position (and now, if 6 depth informations are available, how to distribute it in a right way, to cover the whole space?)   vec3 depth = vDepthPosition.xyz / vDepthPosition.w; depth.z = length(vWorldVertex.xyz - uLightPosition) * linearDepthConstant; 8. If the distance between the vertex and the light position is greater than the distance stored in an unpacked distance from shadow map, the vertex is in shadow.   float shadowDepth = unpack(texture2D(uDepthMapSampler, depth.xy)); if (depth.z > shadowDepth) shadow = 0.5; --------- --- Could you give me some hints or examples (preferably in OpenGL ES 2.0 or WebGL) how I should build it?   **UPDATE:** I figured out that view matrices are superfluous in the case of program rendering the scene with shadows. One can read the adequate texel from the shadow cubemap by using one of those vectors: `lightPosition - worldVertexPosition` or `worldVertexPosition - lightPosition` (right now I don't know which is the correct one, because both gives a not complete shadowing result - the first one mirrors the shadow and doesn't display anything from the -Y light cubemap face while the second one displays the bottom face correctly, but it does right only that)   shadowDepth = unpack(textureCube(uDepthCubemapSampler, vWorldVertex.xyz - uLightPosition)); or shadowDepth = unpack(textureCube(uDepthCubemapSampler, uLightPosition - vWorldVertex.xyz));  
  7. I decided to totally abandon the wrapFunction idea 'cause warping a function just like this: function(args) { doSomething(args) } works flawlessly, it's easier to type, easier to understand and generally it's more suitable for me ;]
  8. The method you have provided, DareDeveloper, still requires to pass the function's 'parent', which is what I'm trying to avoid, because I feel that there should be a simple way to get the reference's origin.
  9. When I need to pass a function with parameters as a parameter to another function I use a partial function application function, which looks like this: function wrapFunction(func, params) { // 'params' should be an array return function() { return func.apply(this, params); }; } This works fine when passing a function like alert(arg), which is not a prototype of any object (as far as I'm convinced). But as soon as I need to pass a prototype function of an object, for example camera.moveTowards(arg1, arg2, ...), argument 'this' in wrapFunction() needs to be replaced by 'camera'. Is there any way to get a reference to a prototype's parent and pass it in place of 'this'?   PS: I don't want to add another argument to wrapFunction, which I would declare every time (like wrapFunction(camera, camera.moveTowards, [arg1, arg2, ...])), because it messes up the readability.
  10. I have kinda solved the problem - instead of using quaternions by themselves I have calculated a new vector between the forward vector and the vector pointing to the model using a modified spherical interpolation method (instead of passing a fraction I pass an angular speed) and then calculated a lookAt matrix like in this article http://stackoverflow.com/questions/349050/calculating-a-lookat-matrix . Now I'm just still wondering what is wrong with the quaternion method. I hope that my actual solution doesn't introduce Gimbal Lock problem.   Code of my current rotateTowards function: rotateTowards: function(target, angularSpeed) { if (this.position.isEqual(target)) { // If is on the same position return; } var vecStart = this.rotation.getForwardVector(); var vecTarget = this.position.sub(target).normalize(); var angleLeft = Math.acos(vecStart.dot(vecTarget)); var fullAngle = angularSpeed * deltaT; if (Math.areScalarsSimilar(angleLeft, 0)) { // If already rotated towards the target return; } else if (Math.areScalarsSimilar(angleLeft, Math.PI)) { // If vectors are opposite // Turn around up-axis a bit this.rotation.multiply(new Quaternion().axisToQuaternion(fullAngle, upVec())); MVMatrix.setRotation(this.rotation.quaternionToMatrix()); } else { // If vectors casually differs if (angleLeft > fullAngle) { // If able to make another full rotation step var zAxis = new vec3().angularSlerp(vecStart, vecTarget, fullAngle); var xAxis = upVec().cross(zAxis).normalize(); var yAxis = zAxis.cross(xAxis); MVMatrix.make( xAxis.x, xAxis.y, xAxis.z, yAxis.x, yAxis.y, yAxis.z, zAxis.x, zAxis.y, zAxis.z, this.position.x, this.position.y, this.position.z); this.rotation.matrixToQuaternion(MVMatrix); this.pitch = this.rotation.getPitch(); this.yaw = this.rotation.getYaw(); this.adjustAngles(); } else { // If the angle left is smaller than the angular speed // Set the final rotation this.lookAt(target); } } }, And the simple angularSlerp function: angularSlerp: function(v0, v1, angularSpeed) { var angleBetween = Math.acos(v0.dot(v1)); v0.multiplyByScalar(Math.sin(angleBetween - angularSpeed)/Math.sin(angleBetween)); v1.multiplyByScalar(Math.sin(angularSpeed)/Math.sin(angleBetween)); return v0.add(v1); },
  11. I'm building a framework for my WebGL project and at the moment I have a problem with a function which will rotate an object towards a target vector with a given angular speed.    In Unity engine it's called rotateTowards(), and since I'm coding my framework from a scratch, I'm basing on my observations about how this function works.    Lately I have abandoned an idea about interpolating two quaternions in this function using nLERP method, because an angular speed seems to be far more suitable factor.    The function seems to be almost working - it works well only when there is no roll or pitch angle in the camera rotation involved, otherwise it makes strange curves and sets the final position after ridiculously long time. After some time I've figured out that the problem must be lying in a conversion of an axis-angle info to quaternion, but the function is not coded wrong by itself, because a 6DOF camera mode works flawlesly using this function (`this.rotation.multiply(this.tempQuat.axisToQuaternion(radY, rightVec()));`), so I guess that the problem may be in the rotation axis. Is this the right way to code this function?   How does it look like? http://i.stack.imgur.com/IC56J.gif   PS For camera, I store pitch and yaw in separate variables because I don't want any roll to appear.   The code of this function below: rotateTowards: function(target, angularSpeed) { // TODO // If is on the same position if (this.position.isEqual(target)) { return; } var vecStart = this.rotation.getForwardVector(); var vecTarget = this.position.sub(target).normalize(); var angleLeft = Math.acos(vecStart.dot(vecTarget)); var fullAngle = angularSpeed * deltaT; // If already rotated towards the target if (Math.areScalarsSimilar(angleLeft, 0)) { return; } // If vectors are opposite else if (Math.areScalarsSimilar(angleLeft, Math.PI)) { // Turn around up-axis this.rotation.multiply(new Quaternion().axisToQuaternion(fullAngle, upVec())); } // If vectors casually differs else { var rotAxis = vecStart.cross(vecTarget); // If able to make another full rotation step if (angleLeft > fullAngle) { this.tempQuat.axisToQuaternion(fullAngle, rotAxis); this.pitch += this.tempQuat.getPitch(); this.yaw += this.tempQuat.getYaw(); this.adjustAngles(); this.rotation.pitchYawRollToQuaternion(this.pitch, this.yaw, 0); log(vecStart.toString()); } // If the angle left is smaller than the angular speed else { // Set the final rotation this.tempQuat.axisToQuaternion(angleLeft, rotAxis); this.pitch += this.tempQuat.getPitch(); this.yaw += this.tempQuat.getYaw(); this.adjustAngles(); this.rotation.pitchYawRollToQuaternion(this.pitch, this.yaw, 0); } } MVMatrix.setRotation(this.rotation.quaternionToMatrix()); }, And a math library that I use: https://www.dropbox.com/s/9ejj64v59xzqn6y/myMath.js
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!