godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.96k stars 21.15k forks source link

PRIMITIVE_POINTS not visible in HTML5 export (3.1.2 and 3.2beta3) #34213

Closed charliewhitfield closed 4 years ago

charliewhitfield commented 4 years ago

Godot version: Problem observed in both 3.1.2 and 3.2-beta3(official) HTML5 exports, GLES2

OS/device including version: Tested using Chrome, Firefox and MSEdge (HTML5 export from Windows 10)

Issue description: PRIMITIVE_POINTS are not visible in HTML5 export in Godot versions tested (3.1.2 and 3.2-beta3), but are visible in editor runs and Windows 10 exports (all GLES2).

My project uses Mesh.PRIMITIVE_POINTS in an ArrayMesh to display asteroids. Here is what it is supposed to look like. (Yes, I know there are a heck of a lot of points! But the problem is the same if I reduce the number of asteroids to just a few hundred.) I Voyager asteroids

Steps to reproduce: In any project using PRIMITIVE_POINTS, export to HTML5.

Minimal reproduction project: ~This is not a minimal project, but you can download "Planetarium" under Godot Projects on the I, Voyager Download page. Run the project and click "All Asteroids" in the panel on the lower right. Sorry, this will take a while to download & import due to image assets. Please let me know if a smaller project is needed for testing.~ EDIT: That's a terrible MRP. Here's a real one: test_primitive_points.zip

charliewhitfield commented 4 years ago

OK, I've come to realize that what I did to make those points is not at all obvious. I'll work up a proper minimal project and post it here shortly.

clayjohn commented 4 years ago

Try building from master and testing. I have a feeling this is the same problem as https://github.com/godotengine/godot/pull/34237

charliewhitfield commented 4 years ago

@clayjohn, I'm not quite up to speed on compiling Godot (I'll get there...). It seem to me a different issue, since this one doesn't seem to be related to distance. And this one isn't a regression (same result in 3.1.2).

Here's an actual minimum reproduction project: test_primitive_points.zip

Windows Export (3.2beta3.official): Screenshot (76)

HTML5 export (3.2beta3.official): Screenshot (75)

The MeshInstance in the test code is created entirely by GDScript, as follows:

extends MeshInstance

func _ready():
    var circle_vertecies1 := PoolVector3Array()
    var circle_vertecies2 := PoolVector3Array()
    var th := 0.0
    for i in range(100):
        th = i * TAU / 100.0
        var vertex := Vector3(sin(th), cos(th), 0.0)
        circle_vertecies1.append(vertex)
        circle_vertecies2.append(vertex / 1.5)

    var points_mesh := ArrayMesh.new()
    var arrays1 := []
    arrays1.resize(ArrayMesh.ARRAY_MAX)
    arrays1[ArrayMesh.ARRAY_VERTEX] = circle_vertecies1
    var arrays2 := []
    arrays2.resize(ArrayMesh.ARRAY_MAX)
    arrays2[ArrayMesh.ARRAY_VERTEX] = circle_vertecies2
    points_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_LINE_LOOP, arrays1, [], VisualServer.ARRAY_FORMAT_VERTEX)
    points_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_POINTS, arrays2, [], VisualServer.ARRAY_FORMAT_VERTEX)
    mesh = points_mesh

EDIT: It wasn't needed in the minimal reproduction project above, but what I do in the solar system simulator is add a shader that sets POINT_SIZE and ALBEDO and updates VERTEX positions each frame.

clayjohn commented 4 years ago

Thanks, I'll test it tonight and let you know how it goes!

clayjohn commented 4 years ago

I am able to reproduce. I think that in HTML POINT_SIZE is defaulting to 0. Because if you set POINT_SIZE to any value, the points appear.

If gl_PointSize is not written to, it is undefined. So I guess it depends on the drivers what it is initialized as. on desktop it must initialize to 1, on web it must initialize to 0.

charliewhitfield commented 4 years ago

~POINT_SIZE is set in my solar system simulator, but they still aren't showing in HTML5 export specifically. Let me see if I can reproduce in the MRP.~

OK, setting POINT_SIZE does fix my MRP in HTML5 export. (Sadly, this does not make my asteroids visible in HTML5 export, but I have to conclude that something entirely different is causing the problem.)

Thank you for your help clayjohn!

clayjohn commented 4 years ago

Likely a combination of this and https://github.com/godotengine/godot/pull/34237. I assume your asteroids are far away from the camera.

charliewhitfield commented 4 years ago

@clayjohn, Would those distances be much different than LINE_LOOP? I think I will have to work up a specific MRP for my asteroids. My current guess is that it has something to do with the way I pass orbital parameters to the shader not working in HTML5. I build the asteroids using ArrayMesh, passing "Keplerian elements" (the fixed, unchanging part) via NORMAL, COLOR, etc. Then I make them orbit by updating only "time" uniform. Here's the shader part (you can see that POINT_SIZE was never the problem here):

// orbit_points.shader
// This file is part of I, Voyager
// https://ivoyager.dev
// Copyright (c) 2017-2019 Charlie Whitfield
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// *****************************************************************************

shader_type spatial;
render_mode unshaded, cull_disabled, skip_vertex_transform;

uniform float time = 0.0;
uniform float point_size = 3.0;
uniform vec3 color = vec3(0.0, 1.0, 0.0);

void vertex() {
    // fixed orbital elements
    float a = NORMAL.x;
    float e = NORMAL.y;
    float i = NORMAL.z;
    float Om = COLOR.x;
    float w = COLOR.y;
    float M0 = COLOR.z;
    float n = COLOR.w;

    float M = M0 + n * time;
    M = mod(M + 3.141592654, 6.283185307) - 3.141592654; // -PI to PI
    float E = M + e * sin(M);
    float dE = (E - M - e * sin(E)) / (1.0 - e * cos(E));
    E -= dE;
    int steps = 1;
    while (abs(dE) > 1e-5 && steps < 10) {
        // Some TNOs never converge w/ threshold 1e-6. I think they get close in
        // several steps and then flip between two values outside the threshold,
        // perhaps due to single-precision floats.
        dE = (E - M - e * sin(E)) / (1.0 - e * cos(E));
        E -= dE;
        steps += 1;
    }
    float nu = 2.0 * atan(sqrt((1.0 + e) / (1.0 - e)) * tan(E / 2.0));
    float r = a * (1.0 - e * cos(E));
    float cos_i = cos(i);
    float sin_Om = sin(Om);
    float cos_Om = cos(Om);
    float sin_w_nu = sin(w + nu);
    float cos_w_nu = cos(w + nu);
    float x = r * (cos_Om * cos_w_nu - sin_Om * sin_w_nu * cos_i);
    float y = r * (sin_Om * cos_w_nu + cos_Om * sin_w_nu * cos_i);
    float z = r * sin(i) * sin_w_nu;
    VERTEX = (MODELVIEW_MATRIX * vec4(x, y, z, 1.0)).xyz;
    POINT_SIZE = point_size;
}

void fragment() {
    ALBEDO = color;
}
clayjohn commented 4 years ago

What im saying is, I think your running into two bugs at once. 1) is that points were not showing at all on web without a default size and 2) is that points that are far away are disappearing.

You need both fixes to be merged before you can test.

charliewhitfield commented 4 years ago

I got you. You can certainly close this issue.

I may post an asteroid MRP here later anyway. But I'll also compile Godot (about time for me to learn that) and try with your new fixes.

clayjohn commented 4 years ago

We'll close the issue when #34262 is merged :) then you can double check that it works with a nightly build.

charliewhitfield commented 4 years ago

I will do that. I did make a new MRP, if you are willing to indulge me in one more test... asteroid_test.zip

capnm commented 4 years ago

I did make a new MRP, if you are willing to indulge me in one more test... while (abs(dE) > 1e-5 && steps < 10) {

gles2 compiles to webgl1, which doesn't support dynamic loops. Don't do that if you want to export gles2 to HTML.

charliewhitfield commented 4 years ago

@capnm, That was the problem. Thank you!

Should this be documented? I would not have figured that out without expert knowledge. There is no hint of this in either Shading Language: Flow control nor Export for the Web: Limitations.

clayjohn commented 4 years ago

Should definitely be documented. Please make a post in the godot-docs repo. :)