Mikal's Forum Posts

  • Another alternative is to have an option to have the vertex shader pass the pos value to the fragment shader and then allow the user to define the fragment shader used during the 3D Shape and Mesh predraw.

  • The newer 3D additions to C3 have opened up many visual possibilities to doing 3D games + C3 2D game logic / collision, etc.

    One drawback for the 3D rendering has been the issue that there is no lighting, so the 3D objects can sometimes look flat, losing the feeling of depth, because all the sides of a 3D shape have the same intensity and they can blend together.

    I would like to suggest one idea that could help, add a single light lighting shader as an option for the default vertex and fragment shaders that are using during predraw of 3D Shapes or 3D Meshes. Doing it on the GPU per fragment can make the lighting more subtle and does not take up CPU performance.

    To test this out just for proof of concept, I changed the C3 default vertex and fragment shaders. The vertex shader was changed to pass the position. The fragment shader was changed to calculate the fragment normal from pos based on dfdy and dfdx and then simple point / spotlight lighting with attenuation was applied (with a little bonus of creating normals from texture changes to make surfaces look a little more interesting, this could be removed.)

    It looks pretty decent and adds a nice feeling of depth to the 3D Shape and Mesh geometry.

    I think it could get complicated with more lights, but being able to define a single light would go a long way.

    Below is an example based on the latest complex terrain example (w/ higher resolution viewport and textures.)

    Subscribe to Construct videos now

    These could be applied when doing the pre draw for Mesh and 3D types of objects (3DShape and others).

    Ashley - if you want to do some quick testing, here is the simple test code, you can also contact me to get a test project if you are interested.

     return [`#version 300 es`, `in highp vec3 aPos;`, `in ${texPrecision} vec2 aTex;`, `out ${texPrecision} vec2 vTex;`, `out highp vec3 pos;`, `uniform highp mat4 matP;`, `uniform highp mat4 matMV;`, `void main(void) {`, ` gl_Position = matP * matMV * vec4(aPos, 1.0);`, ` vTex = aTex;`, ` pos = aPos;`, `}`].join("\n")
    
    
    return[
    "#version 300 es",
    "in mediump vec2 vTex;in highp vec3 pos;",
    "out lowp vec4 outColor;",
    "uniform lowp vec4 color;",
    "uniform lowp sampler2D samplerFront;",
    "uniform highp vec2 pixelSize;",
    "highp float luminance(in highp vec3 c)",
    "{",
    "	return dot(c, vec3(.2126, .7152, .0722));",
    "}",
    
    "highp vec3 normalColor(in highp vec2 uv, sampler2D nSampler)",
    "{",
    "highp vec2 s = pixelSize;",
    
    "	const highp vec2 size = vec2(2.0,0.0);",
    "	const highp vec3 off = vec3(-1.,0.,1.);",
    
    "highp float s11 = luminance(texture(nSampler,uv).xyz);",
    "highp float s01 = luminance(texture(nSampler, uv+off.xy*0.0001).xyz);",
    "highp float s10 = luminance(texture(nSampler, uv+off.yx*0.0001).xyz);",
    
    "highp vec3 va = (vec3(size.xy*0.001, s01 - s11));",
    "highp vec3 vb = (vec3(size.yx*0.001, s10 - s11));",
    
    "highp vec3 normalV = normalize(cross(va, vb));",
     
    "	return normalV;",
    "}",
    "void main(void) {",
    	"highp vec3 lightPos = vec3(300.,100.,800.);",
    	"highp vec3 lightDir = pos-lightPos;",
    	"highp float lightDist = length(lightDir);",
    	"lightDir = normalize(lightDir);",
    	"highp vec3 spotDir = vec3(0,0.7,-1.);",
    	"spotDir = normalize(spotDir);",
    	"highp vec3 dx = dFdx(pos);",
    	"highp vec3 dy = dFdy(pos);",
    	"highp vec3 worldSpaceNormal = normalize(cross(dx, dy));",
    	"worldSpaceNormal = worldSpaceNormal + 0.15 * normalColor(vTex, samplerFront);",
    	"worldSpaceNormal = normalize(worldSpaceNormal);",
    	"lowp vec4 tex = texture(samplerFront, vTex);",
    	"highp float light = dot(worldSpaceNormal,lightDir) * 0.5 + 0.5;",
    	"light = light*light;",
    	"highp float cutoff = 0.90; highp float edge = 0.3;",
    	"highp float spot = dot(spotDir, lightDir);",
    	"spot = spot < cutoff ? smoothstep(cutoff*(1.-edge), cutoff, spot) : 1.0;",
    	"light = light * spot;",
    	"light = light / (1.0 * 1.0 + lightDist * 0.00000001 + lightDist * lightDist * 0.000001);",
    	"light = light < 0.05 ? 0.05 : light;",
    	"outColor = vec4(light * tex.xyz, tex.a);",
    	"gl_FragDepth = (outColor.a == 0.0 ? 1.0 : gl_FragCoord.z);",
    "}"]
    .join("\n")
    
  • Typically the main issue is that you need to use Spine 4.1 and Spine 4.1 export.

  • Due to C3 SDK limitations,

    - Normals are not supported (per vertex or normalmap)

    - Vertex colors are not supported

    Hope it is still useful for you.

    Also side note, I tested basic functionality with webGPU renderer and with a change for the new SDK, it works, but performance seems to regress, so investigating.

  • This was fun, nice example to modify from C3!

    Subscribe to Construct videos now

    3DObject (my addon):

    kindeyegames.itch.io/c3-3dobject-alpha

  • That version only works in later beta versions of C3, which I think I mentioned in the dev log.

  • Thanks for the fix, it looks this addon will be user supported going forward, which is fine, together I think we can figure out any issues.

  • Ah, I think it not an issue of them not getting rendered, it is the issue of the depth value behind the effect outline pixel being 1, so the fog effect goes to the maximum value and the red outline is mixed to the full fog color.

  • This is an interesting and complicated problem based on the C3 3D render and how the first fragment shader handles transparency for 3D rendering, intermediate renders, depth buffer and fog render.

    Tech details below, with a trace of the C3 rendering.

    This is probably not exactly correct, but I think it is something along these lines.

    Some more 3D transparency 'fun', when rendering effects like outline, the first render to an intermediate buffer writes to the depth buffer, but since the outline is not enabled yet, the area of the outline does not write to the z buffer. Later when the effect is rendered into the frame buffer the outline is applied, but the z values from the intermediate render are not set in the outline region (they are 1, max distance). Later when the fog (?) is rendered, even though it should be behind the zombie (and the outline) with a lower z, it renders 'over' the outline at the bottom, because the 'z' is not set for the outline. The outline for around the zombie against the wall works, because the wall is rendered first before the zombie and sets z values, so when the fog (?) is rendered later it does not write over the pixels. Whew, hmmm how to fix.

  • essencescape nice work figuring it out. When you are ready, it would be nice to see what you are doing with the Spine addon, feel free to post results into this thread.

    In terms of slot colors, also look at doing two color tint, this requires you to also add a 'tint black' to the slots you want to color. Dark color allows more effects to be done, definitely some interesting ones.

    twitter.com/EsotericSoft/status/802960853242822656

    en.esotericsoftware.com/blog/Spine-3.6-tint-black-clipping-weight-painting-and-more

  • Can you share your project? I typically create a custom skin, add the other skin variations I want to that custom skin and then set the custom skin.

    If you want to DM, the project, I am Mikal#1464 on Discord and on the Construct Community Discord server.

  • Note that the Spine object will _not_ render in the editor, it will only render during runtime, due to limitations of how the Spine render interacts with the C3 render.

    That being said, if you are having an issue during runtime, you can send a link to the project and I can take a look for you.

  • When you go to the local server do you use http and ws instead of https and wss?

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • Yes, I run a server locally along side the client in preview, we use ws: and http: instead of wss and https locally.

  • sTARKi - can you share an example file showing the issues, I want to make sure I am addressing your specific use case. I use sendgb.com to send large files, or you can DM me on the Construct Community Discord.