Skip to content

Commit

Permalink
Initial gpu texture generation.
Browse files Browse the repository at this point in the history
  • Loading branch information
Gamenot committed Oct 3, 2023
1 parent 5d4b56b commit cae52c5
Show file tree
Hide file tree
Showing 5 changed files with 254 additions and 19 deletions.
30 changes: 24 additions & 6 deletions examples/occlusion/mask.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,14 +527,30 @@ def __init__(self, inner_agent, mode, observation_radius=40) -> None:

@lru_cache(1)
def _get_perlin(
self, width, height, smooth_iterations, seed, table_dim, shift, amplitude=5, granularity=0.02
self,
width,
height,
smooth_iterations,
seed,
table_dim,
shift,
amplitude=5,
granularity=0.02,
):
# from smarts.sstudio.graphics.perlin_bytemap import generate_perlin

# return generate_perlin(width, height, smooth_iterations, seed, table_dim, shift)
from smarts.sstudio.graphics.perlin_bytemap import generate_simplex

return generate_simplex(width, height, seed, shift, octaves=2, amplitude=amplitude, granularity=granularity)
return generate_simplex(
width,
height,
seed,
shift,
octaves=2,
amplitude=amplitude,
granularity=granularity,
)

def _rotate_image(self, heightfield: HeightField, heading: float):
image = Image.fromarray(heightfield.data, "L")
Expand All @@ -546,7 +562,6 @@ def _rotate_image(self, heightfield: HeightField, heading: float):
)

def act(self, obs: Optional[Observation], **configs):

img_width, img_height = (
obs.drivable_area_grid_map.metadata.width,
obs.drivable_area_grid_map.metadata.height,
Expand Down Expand Up @@ -579,7 +594,9 @@ def act(self, obs: Optional[Observation], **configs):

vehicle_hf = HeightField.from_rgb(obs.occupancy_grid_map.data)
height_scaling = 5
drivable_hf = HeightField(obs.drivable_area_grid_map.data, (img_width, img_height))
drivable_hf = HeightField(
obs.drivable_area_grid_map.data, (img_width, img_height)
)
edge_hf = generate_edge_from_heightfield(
drivable_hf,
far_kernel(),
Expand Down Expand Up @@ -612,7 +629,9 @@ def act(self, obs: Optional[Observation], **configs):
amplitude=int(2 * height_scaling),
granularity=0.5,
)
offroad_hf = self._rotate_image(offroad_perlin, -ego_heading).scale_by(drivable_hf.inverted())
offroad_hf = self._rotate_image(offroad_perlin, -ego_heading).scale_by(
drivable_hf.inverted()
)
hf = edge_hf.add(perlin_hf).max(vehicle_hf).max(offroad_hf)

los = hf.to_line_of_sight(
Expand Down Expand Up @@ -860,7 +879,6 @@ def consume(video_source_pattern="A1_%d.jpg", video_name="sd_obs.mp4"):


def dummy_main(output_file):

import gymnasium as gym

from smarts.env.gymnasium.hiway_env_v1 import HiWayEnvV1
Expand Down
58 changes: 58 additions & 0 deletions smarts/core/glsl/simplex.comp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// The MIT License
// Copyright © 2013 Inigo Quilez
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// https://www.youtube.com/c/InigoQuilez
// https://iquilezles.org


// Simplex Noise (http://en.wikipedia.org/wiki/Simplex_noise), a type of gradient noise
// that uses N+1 vertices for random gradient interpolation instead of 2^N as in regular
// latice based Gradient Noise.

// All noise functions here:
//
// https://www.shadertoy.com/playlist/fXlXzf&from=0&num=12
#version 430

layout (local_size_x = 16, local_size_y = 16)

uniform writeonly image2D toNoise;

vec2 hash( vec2 p ) // replace this by something better
{
p = vec2( dot(p,vec2(127.1,311.7)), dot(p,vec2(269.5,183.3)) );
return -1.0 + 2.0*fract(sin(p)*43758.5453123);
}

float noise( in vec2 p )
{
const float K1 = 0.366025404; // (sqrt(3)-1)/2;
const float K2 = 0.211324865; // (3-sqrt(3))/6;

vec2 i = floor( p + (p.x+p.y)*K1 );
vec2 a = p - i + (i.x+i.y)*K2;
float m = step(a.y,a.x);
vec2 o = vec2(m,1.0-m);
vec2 b = a - o + K2;
vec2 c = a - 1.0 + 2.0*K2;
vec3 h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );
vec3 n = h*h*h*h*vec3( dot(a,hash(i+0.0)), dot(b,hash(i+o)), dot(c,hash(i+1.0)));
return dot( n, vec3(70.0) );
}

void main() {
// get the coordinates
ivec2 texelCoords = ivec2(gl_GlobalInvocationID.xy)

uv *= 5.0;
mat2 m = mat2( 1.6, 1.2, -1.2, 1.6 );
f = 0.5000*noise( uv ); uv = m*uv;
f += 0.2500*noise( uv ); uv = m*uv;
f += 0.1250*noise( uv ); uv = m*uv;
f += 0.0625*noise( uv ); uv = m*uv;

f = 0.5 + 0.5*f;


imageStore(toNoise, texelCoords, vec4(f, f, f, 1.0))
}
106 changes: 106 additions & 0 deletions smarts/core/glsl/surface_facing.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// The MIT License
// Copyright © 2013 Inigo Quilez
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// https://www.youtube.com/c/InigoQuilez
// https://iquilezles.org


// Simplex Noise (http://en.wikipedia.org/wiki/Simplex_noise), a type of gradient noise
// that uses N+1 vertices for random gradient interpolation instead of 2^N as in regular
// latice based Gradient Noise.

// All noise functions here:
//
// https://www.shadertoy.com/playlist/fXlXzf&from=0&num=12
//#define SEE_DIRECTION // See the direction to the pixel
#define SHADERTOY
#define CENTER 0.5
#define HEIGHT 1.0
#define RECIPROCAL_BYTE 0.0039215686274509803921568627451

vec2 hash( vec2 p ) // replace this by something better
{
p = vec2( dot(p,vec2(127.1,311.7)), dot(p,vec2(269.5,183.3)) );
return -1.0 + 2.0*fract(sin(p)*43758.5453123);
}

float noise( in vec2 p )
{
const float K1 = 0.366025404; // (sqrt(3)-1)/2;
const float K2 = 0.211324865; // (3-sqrt(3))/6;

vec2 i = floor( p + (p.x+p.y)*K1 );
vec2 a = p - i + (i.x+i.y)*K2;
float m = step(a.y,a.x);
vec2 o = vec2(m,1.0-m);
vec2 b = a - o + K2;
vec2 c = a - 1.0 + 2.0*K2;
vec3 h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );
vec3 n = h*h*h*h*vec3( dot(a,hash(i+0.0)), dot(b,hash(i+o)), dot(c,hash(i+1.0)));
return dot( n, vec3(70.0) );
}

float noise_with_octaves( in vec2 uv, in mat2 m ){
float f = 0.0;
uv *= 5.0;

f = 0.5000*noise( uv ); uv = m*uv;
f += 0.2500*noise( uv ); uv = m*uv;
f += 0.1250*noise( uv ); uv = m*uv;
f += 0.0625*noise( uv ); uv = m*uv;
return f;
}

// -----------------------------------------------

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 rec_res = 1.0 / iResolution.xy;
vec2 p = fragCoord.xy * rec_res;
float aspect = iResolution.x/iResolution.y;

#ifdef SHADERTOY
vec2 uv = p*vec2(aspect,1.0) + vec2(iTime * 0.1);
#else
vec2 uv = p*vec2(aspect,1.0);
#endif


// Determine the minimum delta needed to determine the facing direction of the surface
float interpolate_delta = 1.0 * min(rec_res.x, rec_res.y);
vec2 direction = normalize(p - vec2(0.5));
vec2 uv_offset_to_closer_p = direction * (interpolate_delta)*vec2(aspect,1.0);

#ifdef SEE_DIRECTION
uv_offset_to_closer_p *= 1000.0;
fragColor = vec4(uv_offset_to_closer_p, 0, 1.0);
return;
#endif

float f = 0.0;
float x, y, z;
mat2 m = mat2( 1.6, 1.2, -1.2, 1.6 );

f = noise_with_octaves(uv, m);
// inspect fragments near mouse
if( distance(fragCoord, iMouse.xy) < 30.0 )
{
f = 0.5 + 0.5*f;
f *= 0.3 + f;
fragColor = vec4( f, f, f, 1.0 );
}
else {
float o = noise_with_octaves(uv - uv_offset_to_closer_p, m);
vec3 c = cross(
//vec3(direction.y, -direction.x, 0),
vec3(1, 0, 0),
normalize(vec3(interpolate_delta, 0, (f - o) * RECIPROCAL_BYTE))
);
fragColor = vec4(c.yyy * 25.5, 1.0);
}


if( distance(fragCoord, iResolution.xy/2.0) < 4.0 ) {
fragColor += vec4(0.4, 0.0, 0.0, 1.0);
}
}
12 changes: 7 additions & 5 deletions smarts/sstudio/graphics/heightfield.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def _get_sample_averaging_function(

return self._direct_4_point_coordinate_sample

def _sample_line(
def _data_sample_line(
self,
change_normalized,
resolution,
Expand All @@ -167,9 +167,9 @@ def _sample_line(
viewer_coordinate,
factor,
):
inverse_resolution = 1 / resolution
dist = int(magnitude * inverse_resolution)
for i in range(1, dist):
"""Generates samples on the line between `viewer_coordinate`(excluded) and the end point `viewer_coordinate*magnitude*change_normalized`(excluded)"""
dist = int(magnitude * np.reciprocal(resolution))
for i in range(1, dist - 1):
intermediary_coordinate = change_normalized * i + viewer_coordinate
yield sample_function(intermediary_coordinate), i * factor

Expand Down Expand Up @@ -200,11 +200,13 @@ def data_line_of_sight(
factor = resolution / magnitude

uv_slope_normalized = np.multiply(change, factor)
# MTA TODO: reverse iteration
# Cull opposite facing surfaces (on target surface) to short circuit ray marching
return line_of_sight_test(
viewer_height,
target_height,
magnitude,
self._sample_line(
self._data_sample_line(
uv_slope_normalized,
resolution,
magnitude,
Expand Down
67 changes: 59 additions & 8 deletions smarts/sstudio/graphics/perlin_bytemap.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import argparse
import importlib.resources as pkg_resources
import os
from functools import lru_cache
from typing import Tuple
Expand Down Expand Up @@ -126,9 +127,52 @@ def generate_perlin(
return hf


def generate_simplex_p3d_gpu(
width: int,
height: int,
seed,
shift: Tuple[float, float],
octaves: float = 2,
granularity=0.02,
amplitude=4,
transformation_matrix: np.ndarray = np.identity(4),
):
assert height % 16 == 0
assert width % 16 == 0

from panda3d.core import ComputeNode, Shader, ShaderAttrib, Texture

from smarts.core import glsl
from smarts.p3d.renderer import DEBUG_MODE, Renderer

renderer = Renderer("noise renderer", debug_mode=DEBUG_MODE.ERROR)
renderer._ensure_root()

toNoiseTex = Texture("noise-texture")
toNoiseTex.setup_2d_texture(width, height, Texture.T_unsigned_byte, Texture.F_r8i)
toNoiseTex.set_clear_color((0, 0, 0, 0))

node = ComputeNode("simplex")
node.add_dispatch(width // 16, height // 16, 1)
node_path = renderer._root_np.attach_new_node(node)

with pkg_resources.path(glsl, "simplex.comp") as simplex_shader:
shader = Shader.load_compute(Shader.SL_GLSL, str(simplex_shader.absolute()))
node_path.set_shader(shader)
node_path.set_shader_input("toNoise", toNoiseTex)

sattr = node_path.getAttrib(ShaderAttrib)
# renderer.render()
gsg = renderer._showbase_instance.win.get_gsg()
assert gsg.get_supports_compute_shaders(), f"renderer {gsg.get_class_type().name}"
renderer._showbase_instance.graphics_engine.dispatch_compute(
(32, 32, 1), sattr, gsg
)


def generate_simplex(
width,
height,
width: int,
height: int,
seed,
shift: Tuple[float, float],
octaves: float = 2,
Expand Down Expand Up @@ -179,8 +223,8 @@ def generate_perlin_file(
description="Utility to export mesh files to bytemap.",
)
parser.add_argument("output_path", help="where to write the bytemap file", type=str)
parser.add_argument("--width", help="the width pixels", type=int, default=100)
parser.add_argument("--height", help="the height pixels", type=int, default=100)
parser.add_argument("--width", help="the width pixels", type=int, default=256)
parser.add_argument("--height", help="the height pixels", type=int, default=256)
parser.add_argument(
"--smooth_iterations", help="smooth the output", type=int, default=0
)
Expand All @@ -202,12 +246,19 @@ def generate_perlin_file(
if args.match_file_dimensions != "":
width, height = get_image_dimensions(args.match_file_dimensions)

generate_perlin_file(
args.output_path,
# generate_perlin_file(
# args.output_path,
# width,
# height,
# args.smooth_iterations,
# args.seed,
# args.table_dim,
# args.shift,
# )

generate_simplex_p3d_gpu(
width,
height,
args.smooth_iterations,
args.seed,
args.table_dim,
args.shift,
)

0 comments on commit cae52c5

Please sign in to comment.